1use crate::block::BlockRoot;
4use crate::hashes::Blake3Hash;
5use crate::pieces::RecordChunk;
6use ab_blake3::single_block_hash;
7use ab_io_type::trivial_type::TrivialType;
8use core::iter::Step;
9use core::num::{NonZeroU8, NonZeroU32};
10use core::str::FromStr;
11use core::time::Duration;
12use core::{fmt, mem};
13use derive_more::{
14 Add, AddAssign, AsMut, AsRef, Deref, DerefMut, Display, Div, DivAssign, From, Into, Mul,
15 MulAssign, Sub, SubAssign,
16};
17#[cfg(feature = "scale-codec")]
18use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
19#[cfg(feature = "scale-codec")]
20use scale_info::TypeInfo;
21#[cfg(feature = "serde")]
22use serde::{Deserialize, Serialize};
23#[cfg(feature = "serde")]
24use serde::{Deserializer, Serializer};
25
26#[derive(
28 Debug, Display, Default, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From, Into,
29)]
30#[cfg_attr(
31 feature = "scale-codec",
32 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
33)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35#[repr(C)]
36pub struct SlotDuration(u16);
37
38impl SlotDuration {
39 pub const SIZE: usize = size_of::<u16>();
41
42 #[inline(always)]
44 pub const fn from_millis(ms: u16) -> Self {
45 Self(ms)
46 }
47
48 #[inline(always)]
50 pub const fn as_millis(self) -> u16 {
51 self.0
52 }
53
54 #[inline(always)]
56 pub const fn as_duration(self) -> Duration {
57 Duration::from_millis(self.as_millis() as u64)
58 }
59}
60
61#[derive(
63 Debug,
64 Display,
65 Default,
66 Copy,
67 Clone,
68 Ord,
69 PartialOrd,
70 Eq,
71 PartialEq,
72 Hash,
73 From,
74 Into,
75 Add,
76 AddAssign,
77 Sub,
78 SubAssign,
79 Mul,
80 MulAssign,
81 Div,
82 DivAssign,
83 TrivialType,
84)]
85#[cfg_attr(
86 feature = "scale-codec",
87 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
88)]
89#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
90#[repr(C)]
91pub struct SlotNumber(u64);
92
93impl Step for SlotNumber {
94 #[inline(always)]
95 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
96 u64::steps_between(&start.0, &end.0)
97 }
98
99 #[inline(always)]
100 fn forward_checked(start: Self, count: usize) -> Option<Self> {
101 u64::forward_checked(start.0, count).map(Self)
102 }
103
104 #[inline(always)]
105 fn backward_checked(start: Self, count: usize) -> Option<Self> {
106 u64::backward_checked(start.0, count).map(Self)
107 }
108}
109
110impl From<SlotNumber> for u128 {
111 #[inline(always)]
112 fn from(original: SlotNumber) -> Self {
113 u128::from(original.0)
114 }
115}
116
117impl SlotNumber {
118 pub const SIZE: usize = size_of::<u64>();
120 pub const ZERO: Self = Self(0);
122 pub const ONE: Self = Self(1);
124 pub const MAX: Self = Self(u64::MAX);
126
127 #[inline(always)]
129 pub const fn new(n: u64) -> Self {
130 Self(n)
131 }
132
133 #[inline(always)]
135 pub const fn as_u64(self) -> u64 {
136 self.0
137 }
138
139 #[inline(always)]
141 pub const fn from_bytes(bytes: [u8; Self::SIZE]) -> Self {
142 Self(u64::from_le_bytes(bytes))
143 }
144
145 #[inline(always)]
147 pub const fn to_bytes(self) -> [u8; Self::SIZE] {
148 self.0.to_le_bytes()
149 }
150
151 #[inline(always)]
153 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
154 if let Some(n) = self.0.checked_add(rhs.0) {
155 Some(Self(n))
156 } else {
157 None
158 }
159 }
160
161 #[inline(always)]
163 pub const fn saturating_add(self, rhs: Self) -> Self {
164 Self(self.0.saturating_add(rhs.0))
165 }
166
167 #[inline(always)]
169 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
170 if let Some(n) = self.0.checked_sub(rhs.0) {
171 Some(Self(n))
172 } else {
173 None
174 }
175 }
176
177 #[inline(always)]
179 pub const fn saturating_sub(self, rhs: Self) -> Self {
180 Self(self.0.saturating_sub(rhs.0))
181 }
182}
183
184#[derive(Default, Copy, Clone, Eq, PartialEq, From, Into, AsRef, AsMut, Deref, DerefMut)]
186#[cfg_attr(
187 feature = "scale-codec",
188 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
189)]
190pub struct PotKey([u8; PotKey::SIZE]);
191
192impl fmt::Debug for PotKey {
193 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194 for byte in self.0 {
195 write!(f, "{byte:02x}")?;
196 }
197 Ok(())
198 }
199}
200
201#[cfg(feature = "serde")]
202#[derive(Serialize, Deserialize)]
203#[serde(transparent)]
204struct PotKeyBinary([u8; PotKey::SIZE]);
205
206#[cfg(feature = "serde")]
207#[derive(Serialize, Deserialize)]
208#[serde(transparent)]
209struct PotKeyHex(#[serde(with = "hex")] [u8; PotKey::SIZE]);
210
211#[cfg(feature = "serde")]
212impl Serialize for PotKey {
213 #[inline]
214 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
215 where
216 S: Serializer,
217 {
218 if serializer.is_human_readable() {
219 PotKeyHex(self.0).serialize(serializer)
220 } else {
221 PotKeyBinary(self.0).serialize(serializer)
222 }
223 }
224}
225
226#[cfg(feature = "serde")]
227impl<'de> Deserialize<'de> for PotKey {
228 #[inline]
229 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
230 where
231 D: Deserializer<'de>,
232 {
233 Ok(Self(if deserializer.is_human_readable() {
234 PotKeyHex::deserialize(deserializer)?.0
235 } else {
236 PotKeyBinary::deserialize(deserializer)?.0
237 }))
238 }
239}
240
241impl fmt::Display for PotKey {
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 for byte in self.0 {
244 write!(f, "{byte:02x}")?;
245 }
246 Ok(())
247 }
248}
249
250impl FromStr for PotKey {
251 type Err = hex::FromHexError;
252
253 #[inline]
254 fn from_str(s: &str) -> Result<Self, Self::Err> {
255 let mut key = Self::default();
256 hex::decode_to_slice(s, key.as_mut())?;
257
258 Ok(key)
259 }
260}
261
262impl PotKey {
263 pub const SIZE: usize = 16;
265}
266
267#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, From, Into, AsRef, AsMut, Deref, DerefMut)]
269#[cfg_attr(
270 feature = "scale-codec",
271 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
272)]
273pub struct PotSeed([u8; PotSeed::SIZE]);
274
275impl fmt::Debug for PotSeed {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 for byte in self.0 {
278 write!(f, "{byte:02x}")?;
279 }
280 Ok(())
281 }
282}
283
284#[cfg(feature = "serde")]
285#[derive(Serialize, Deserialize)]
286#[serde(transparent)]
287struct PotSeedBinary([u8; PotSeed::SIZE]);
288
289#[cfg(feature = "serde")]
290#[derive(Serialize, Deserialize)]
291#[serde(transparent)]
292struct PotSeedHex(#[serde(with = "hex")] [u8; PotSeed::SIZE]);
293
294#[cfg(feature = "serde")]
295impl Serialize for PotSeed {
296 #[inline]
297 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
298 where
299 S: Serializer,
300 {
301 if serializer.is_human_readable() {
302 PotSeedHex(self.0).serialize(serializer)
303 } else {
304 PotSeedBinary(self.0).serialize(serializer)
305 }
306 }
307}
308
309#[cfg(feature = "serde")]
310impl<'de> Deserialize<'de> for PotSeed {
311 #[inline]
312 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
313 where
314 D: Deserializer<'de>,
315 {
316 Ok(Self(if deserializer.is_human_readable() {
317 PotSeedHex::deserialize(deserializer)?.0
318 } else {
319 PotSeedBinary::deserialize(deserializer)?.0
320 }))
321 }
322}
323
324impl fmt::Display for PotSeed {
325 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 for byte in self.0 {
327 write!(f, "{byte:02x}")?;
328 }
329 Ok(())
330 }
331}
332
333impl PotSeed {
334 pub const SIZE: usize = 16;
336
337 #[inline]
339 pub fn from_genesis(genesis_block_root: &BlockRoot, external_entropy: &[u8]) -> Self {
340 let mut hasher = blake3::Hasher::new();
341 hasher.update(genesis_block_root.as_ref());
342 hasher.update(external_entropy);
343 let hash = hasher.finalize();
344 let mut seed = Self::default();
345 seed.copy_from_slice(&hash.as_bytes()[..Self::SIZE]);
346 seed
347 }
348
349 #[inline]
351 pub fn key(&self) -> PotKey {
352 let mut key = PotKey::default();
353 key.copy_from_slice(
354 &single_block_hash(&self.0).expect("Less than a single block worth of bytes; qed")
355 [..Self::SIZE],
356 );
357 key
358 }
359}
360
361#[derive(
363 Default,
364 Copy,
365 Clone,
366 Eq,
367 PartialEq,
368 Hash,
369 From,
370 Into,
371 AsRef,
372 AsMut,
373 Deref,
374 DerefMut,
375 TrivialType,
376)]
377#[cfg_attr(
378 feature = "scale-codec",
379 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
380)]
381#[repr(C)]
382pub struct PotOutput([u8; PotOutput::SIZE]);
383
384impl fmt::Debug for PotOutput {
385 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386 for byte in self.0 {
387 write!(f, "{byte:02x}")?;
388 }
389 Ok(())
390 }
391}
392
393#[cfg(feature = "serde")]
394#[derive(Serialize, Deserialize)]
395#[serde(transparent)]
396struct PotOutputBinary([u8; PotOutput::SIZE]);
397
398#[cfg(feature = "serde")]
399#[derive(Serialize, Deserialize)]
400#[serde(transparent)]
401struct PotOutputHex(#[serde(with = "hex")] [u8; PotOutput::SIZE]);
402
403#[cfg(feature = "serde")]
404impl Serialize for PotOutput {
405 #[inline]
406 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
407 where
408 S: Serializer,
409 {
410 if serializer.is_human_readable() {
411 PotOutputHex(self.0).serialize(serializer)
412 } else {
413 PotOutputBinary(self.0).serialize(serializer)
414 }
415 }
416}
417
418#[cfg(feature = "serde")]
419impl<'de> Deserialize<'de> for PotOutput {
420 #[inline]
421 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
422 where
423 D: Deserializer<'de>,
424 {
425 Ok(Self(if deserializer.is_human_readable() {
426 PotOutputHex::deserialize(deserializer)?.0
427 } else {
428 PotOutputBinary::deserialize(deserializer)?.0
429 }))
430 }
431}
432
433impl fmt::Display for PotOutput {
434 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435 for byte in self.0 {
436 write!(f, "{byte:02x}")?;
437 }
438 Ok(())
439 }
440}
441
442impl PotOutput {
443 pub const SIZE: usize = 16;
445
446 #[inline]
448 pub fn derive_global_challenge(&self, slot: SlotNumber) -> Blake3Hash {
449 let mut bytes_to_hash = [0; Self::SIZE + SlotNumber::SIZE];
450 bytes_to_hash[..Self::SIZE].copy_from_slice(&self.0);
451 bytes_to_hash[Self::SIZE..].copy_from_slice(&slot.to_bytes());
452 Blake3Hash::new(
453 single_block_hash(&bytes_to_hash)
454 .expect("Less than a single block worth of bytes; qed"),
455 )
456 }
457
458 #[inline]
460 pub fn seed(&self) -> PotSeed {
461 PotSeed(self.0)
462 }
463
464 #[inline]
466 pub fn seed_with_entropy(&self, entropy: &Blake3Hash) -> PotSeed {
467 let mut bytes_to_hash = [0; Blake3Hash::SIZE + Self::SIZE];
468 bytes_to_hash[..Blake3Hash::SIZE].copy_from_slice(entropy.as_ref());
469 bytes_to_hash[Blake3Hash::SIZE..].copy_from_slice(&self.0);
470 let hash = single_block_hash(&bytes_to_hash)
471 .expect("Less than a single block worth of bytes; qed");
472 let mut seed = PotSeed::default();
473 seed.copy_from_slice(&hash[..Self::SIZE]);
474 seed
475 }
476
477 #[inline]
479 pub fn derive_pot_entropy(&self, solution_chunk: &RecordChunk) -> Blake3Hash {
480 let mut bytes_to_hash = [0; RecordChunk::SIZE + Self::SIZE];
481 bytes_to_hash[..RecordChunk::SIZE].copy_from_slice(solution_chunk.as_ref());
482 bytes_to_hash[RecordChunk::SIZE..].copy_from_slice(&self.0);
483 Blake3Hash::new(
484 single_block_hash(&bytes_to_hash)
485 .expect("Less than a single block worth of bytes; qed"),
486 )
487 }
488
489 #[inline(always)]
491 pub const fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
492 unsafe { mem::transmute(value) }
494 }
495
496 #[inline(always)]
498 pub const fn repr_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
499 unsafe { mem::transmute(value) }
501 }
502}
503
504#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, TrivialType)]
506#[cfg_attr(
507 feature = "scale-codec",
508 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
509)]
510#[repr(C)]
511pub struct PotCheckpoints([PotOutput; PotCheckpoints::NUM_CHECKPOINTS.get() as usize]);
512
513impl PotCheckpoints {
514 pub const SIZE: usize = PotOutput::SIZE * Self::NUM_CHECKPOINTS.get() as usize;
516 pub const NUM_CHECKPOINTS: NonZeroU8 = NonZeroU8::new(8).expect("Not zero; qed");
518
519 #[inline]
521 pub fn output(&self) -> PotOutput {
522 self.0[Self::NUM_CHECKPOINTS.get() as usize - 1]
523 }
524
525 #[inline(always)]
527 pub const fn slice_from_bytes(value: &[[u8; Self::SIZE]]) -> &[Self] {
528 unsafe { mem::transmute(value) }
531 }
532
533 #[inline(always)]
535 pub const fn bytes_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
536 unsafe { mem::transmute(value) }
539 }
540}
541
542#[derive(Debug, Copy, Clone, PartialEq, Eq)]
547#[cfg_attr(
548 feature = "scale-codec",
549 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
550)]
551#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
552#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
553pub struct PotParametersChange {
554 pub slot: SlotNumber,
558 pub slot_iterations: NonZeroU32,
560 pub entropy: Blake3Hash,
562}