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