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]
152 pub fn checked_add(self, rhs: Self) -> Option<Self> {
153 self.0.checked_add(rhs.0).map(Self)
154 }
155
156 #[inline]
158 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
159 self.0.checked_sub(rhs.0).map(Self)
160 }
161}
162
163#[derive(Default, Copy, Clone, Eq, PartialEq, From, Into, AsRef, AsMut, Deref, DerefMut)]
165#[cfg_attr(
166 feature = "scale-codec",
167 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
168)]
169pub struct PotKey([u8; PotKey::SIZE]);
170
171impl fmt::Debug for PotKey {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 for byte in self.0 {
174 write!(f, "{byte:02x}")?;
175 }
176 Ok(())
177 }
178}
179
180#[cfg(feature = "serde")]
181#[derive(Serialize, Deserialize)]
182#[serde(transparent)]
183struct PotKeyBinary([u8; PotKey::SIZE]);
184
185#[cfg(feature = "serde")]
186#[derive(Serialize, Deserialize)]
187#[serde(transparent)]
188struct PotKeyHex(#[serde(with = "hex")] [u8; PotKey::SIZE]);
189
190#[cfg(feature = "serde")]
191impl Serialize for PotKey {
192 #[inline]
193 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194 where
195 S: Serializer,
196 {
197 if serializer.is_human_readable() {
198 PotKeyHex(self.0).serialize(serializer)
199 } else {
200 PotKeyBinary(self.0).serialize(serializer)
201 }
202 }
203}
204
205#[cfg(feature = "serde")]
206impl<'de> Deserialize<'de> for PotKey {
207 #[inline]
208 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
209 where
210 D: Deserializer<'de>,
211 {
212 Ok(Self(if deserializer.is_human_readable() {
213 PotKeyHex::deserialize(deserializer)?.0
214 } else {
215 PotKeyBinary::deserialize(deserializer)?.0
216 }))
217 }
218}
219
220impl fmt::Display for PotKey {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 for byte in self.0 {
223 write!(f, "{byte:02x}")?;
224 }
225 Ok(())
226 }
227}
228
229impl FromStr for PotKey {
230 type Err = hex::FromHexError;
231
232 #[inline]
233 fn from_str(s: &str) -> Result<Self, Self::Err> {
234 let mut key = Self::default();
235 hex::decode_to_slice(s, key.as_mut())?;
236
237 Ok(key)
238 }
239}
240
241impl PotKey {
242 pub const SIZE: usize = 16;
244}
245
246#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, From, Into, AsRef, AsMut, Deref, DerefMut)]
248#[cfg_attr(
249 feature = "scale-codec",
250 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
251)]
252pub struct PotSeed([u8; PotSeed::SIZE]);
253
254impl fmt::Debug for PotSeed {
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 for byte in self.0 {
257 write!(f, "{byte:02x}")?;
258 }
259 Ok(())
260 }
261}
262
263#[cfg(feature = "serde")]
264#[derive(Serialize, Deserialize)]
265#[serde(transparent)]
266struct PotSeedBinary([u8; PotSeed::SIZE]);
267
268#[cfg(feature = "serde")]
269#[derive(Serialize, Deserialize)]
270#[serde(transparent)]
271struct PotSeedHex(#[serde(with = "hex")] [u8; PotSeed::SIZE]);
272
273#[cfg(feature = "serde")]
274impl Serialize for PotSeed {
275 #[inline]
276 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
277 where
278 S: Serializer,
279 {
280 if serializer.is_human_readable() {
281 PotSeedHex(self.0).serialize(serializer)
282 } else {
283 PotSeedBinary(self.0).serialize(serializer)
284 }
285 }
286}
287
288#[cfg(feature = "serde")]
289impl<'de> Deserialize<'de> for PotSeed {
290 #[inline]
291 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
292 where
293 D: Deserializer<'de>,
294 {
295 Ok(Self(if deserializer.is_human_readable() {
296 PotSeedHex::deserialize(deserializer)?.0
297 } else {
298 PotSeedBinary::deserialize(deserializer)?.0
299 }))
300 }
301}
302
303impl fmt::Display for PotSeed {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 for byte in self.0 {
306 write!(f, "{byte:02x}")?;
307 }
308 Ok(())
309 }
310}
311
312impl PotSeed {
313 pub const SIZE: usize = 16;
315
316 #[inline]
318 pub fn from_genesis(genesis_block_root: &BlockRoot, external_entropy: &[u8]) -> Self {
319 let mut hasher = blake3::Hasher::new();
320 hasher.update(genesis_block_root.as_ref());
321 hasher.update(external_entropy);
322 let hash = hasher.finalize();
323 let mut seed = Self::default();
324 seed.copy_from_slice(&hash.as_bytes()[..Self::SIZE]);
325 seed
326 }
327
328 #[inline]
330 pub fn key(&self) -> PotKey {
331 let mut key = PotKey::default();
332 key.copy_from_slice(&blake3::hash(&self.0).as_bytes()[..Self::SIZE]);
333 key
334 }
335}
336
337#[derive(
339 Default,
340 Copy,
341 Clone,
342 Eq,
343 PartialEq,
344 Hash,
345 From,
346 Into,
347 AsRef,
348 AsMut,
349 Deref,
350 DerefMut,
351 TrivialType,
352)]
353#[cfg_attr(
354 feature = "scale-codec",
355 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
356)]
357#[repr(C)]
358pub struct PotOutput([u8; PotOutput::SIZE]);
359
360impl fmt::Debug for PotOutput {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 for byte in self.0 {
363 write!(f, "{byte:02x}")?;
364 }
365 Ok(())
366 }
367}
368
369#[cfg(feature = "serde")]
370#[derive(Serialize, Deserialize)]
371#[serde(transparent)]
372struct PotOutputBinary([u8; PotOutput::SIZE]);
373
374#[cfg(feature = "serde")]
375#[derive(Serialize, Deserialize)]
376#[serde(transparent)]
377struct PotOutputHex(#[serde(with = "hex")] [u8; PotOutput::SIZE]);
378
379#[cfg(feature = "serde")]
380impl Serialize for PotOutput {
381 #[inline]
382 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
383 where
384 S: Serializer,
385 {
386 if serializer.is_human_readable() {
387 PotOutputHex(self.0).serialize(serializer)
388 } else {
389 PotOutputBinary(self.0).serialize(serializer)
390 }
391 }
392}
393
394#[cfg(feature = "serde")]
395impl<'de> Deserialize<'de> for PotOutput {
396 #[inline]
397 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
398 where
399 D: Deserializer<'de>,
400 {
401 Ok(Self(if deserializer.is_human_readable() {
402 PotOutputHex::deserialize(deserializer)?.0
403 } else {
404 PotOutputBinary::deserialize(deserializer)?.0
405 }))
406 }
407}
408
409impl fmt::Display for PotOutput {
410 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411 for byte in self.0 {
412 write!(f, "{byte:02x}")?;
413 }
414 Ok(())
415 }
416}
417
418impl PotOutput {
419 pub const SIZE: usize = 16;
421
422 #[inline]
424 pub fn derive_global_challenge(&self, slot: SlotNumber) -> Blake3Hash {
425 let mut bytes_to_hash = [0; Self::SIZE + SlotNumber::SIZE];
426 bytes_to_hash[..Self::SIZE].copy_from_slice(&self.0);
427 bytes_to_hash[Self::SIZE..].copy_from_slice(&slot.to_bytes());
428 blake3::hash(&bytes_to_hash).into()
429 }
430
431 #[inline]
433 pub fn seed(&self) -> PotSeed {
434 PotSeed(self.0)
435 }
436
437 #[inline]
439 pub fn seed_with_entropy(&self, entropy: &Blake3Hash) -> PotSeed {
440 let mut bytes_to_hash = [0; Blake3Hash::SIZE + Self::SIZE];
441 bytes_to_hash[..Blake3Hash::SIZE].copy_from_slice(entropy.as_ref());
442 bytes_to_hash[Blake3Hash::SIZE..].copy_from_slice(&self.0);
443 let hash = blake3::hash(&bytes_to_hash);
444 let mut seed = PotSeed::default();
445 seed.copy_from_slice(&hash.as_bytes()[..Self::SIZE]);
446 seed
447 }
448
449 #[inline]
451 pub fn derive_pot_entropy(&self, solution_chunk: &RecordChunk) -> Blake3Hash {
452 let mut bytes_to_hash = [0; RecordChunk::SIZE + Self::SIZE];
453 bytes_to_hash[..RecordChunk::SIZE].copy_from_slice(solution_chunk.as_ref());
454 bytes_to_hash[RecordChunk::SIZE..].copy_from_slice(&self.0);
455 blake3::hash(&bytes_to_hash).into()
456 }
457
458 #[inline(always)]
460 pub const fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
461 unsafe { mem::transmute(value) }
463 }
464
465 #[inline(always)]
467 pub const fn repr_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
468 unsafe { mem::transmute(value) }
470 }
471}
472
473#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, TrivialType)]
475#[cfg_attr(
476 feature = "scale-codec",
477 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
478)]
479#[repr(C)]
480pub struct PotCheckpoints([PotOutput; PotCheckpoints::NUM_CHECKPOINTS.get() as usize]);
481
482impl PotCheckpoints {
483 pub const SIZE: usize = PotOutput::SIZE * Self::NUM_CHECKPOINTS.get() as usize;
485 pub const NUM_CHECKPOINTS: NonZeroU8 = NonZeroU8::new(8).expect("Not zero; qed");
487
488 #[inline]
490 pub fn output(&self) -> PotOutput {
491 self.0[Self::NUM_CHECKPOINTS.get() as usize - 1]
492 }
493
494 #[inline(always)]
496 pub const fn slice_from_bytes(value: &[[u8; Self::SIZE]]) -> &[Self] {
497 unsafe { mem::transmute(value) }
500 }
501
502 #[inline(always)]
504 pub const fn bytes_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
505 unsafe { mem::transmute(value) }
508 }
509}
510
511#[derive(Debug, Copy, Clone, PartialEq, Eq)]
513#[cfg_attr(
514 feature = "scale-codec",
515 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
516)]
517#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
518#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
519pub struct PotParametersChange {
520 pub slot: SlotNumber,
524 pub slot_iterations: NonZeroU32,
526 pub entropy: Blake3Hash,
528}