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