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 core::iter::Step;
10use core::num::{NonZeroU8, NonZeroU32};
11use core::str::FromStr;
12use core::time::Duration;
13use core::{fmt, mem};
14use derive_more::{
15 Add, AddAssign, AsMut, AsRef, Deref, DerefMut, Display, Div, DivAssign, From, Into, Mul,
16 MulAssign, Sub, SubAssign,
17};
18#[cfg(feature = "scale-codec")]
19use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
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(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31#[repr(C)]
32pub struct SlotDuration(u16);
33
34impl SlotDuration {
35 pub const SIZE: usize = size_of::<u16>();
37
38 #[inline(always)]
40 pub const fn from_millis(ms: u16) -> Self {
41 Self(ms)
42 }
43
44 #[inline(always)]
46 pub const fn as_millis(self) -> u16 {
47 self.0
48 }
49
50 #[inline(always)]
52 pub const fn as_duration(self) -> Duration {
53 Duration::from_millis(self.as_millis() as u64)
54 }
55}
56
57#[derive(
59 Debug,
60 Display,
61 Default,
62 Copy,
63 Clone,
64 Ord,
65 PartialOrd,
66 Eq,
67 PartialEq,
68 Hash,
69 Add,
70 AddAssign,
71 Sub,
72 SubAssign,
73 Mul,
74 MulAssign,
75 Div,
76 DivAssign,
77 TrivialType,
78)]
79#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
80#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
81#[repr(C)]
82pub struct SlotNumber(u64);
83
84impl Step for SlotNumber {
85 #[inline(always)]
86 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
87 u64::steps_between(&start.0, &end.0)
88 }
89
90 #[inline(always)]
91 fn forward_checked(start: Self, count: usize) -> Option<Self> {
92 u64::forward_checked(start.0, count).map(Self)
93 }
94
95 #[inline(always)]
96 fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
97 let (n, overflowing) = u64::forward_overflowing(start.0, count);
98 (Self(n), overflowing)
99 }
100
101 #[inline(always)]
102 fn backward_checked(start: Self, count: usize) -> Option<Self> {
103 u64::backward_checked(start.0, count).map(Self)
104 }
105
106 #[inline(always)]
107 fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
108 let (n, overflowing) = u64::backward_overflowing(start.0, count);
109 (Self(n), overflowing)
110 }
111}
112
113const impl From<u64> for SlotNumber {
114 #[inline(always)]
115 fn from(value: u64) -> Self {
116 Self(value)
117 }
118}
119
120const impl From<SlotNumber> for u64 {
121 #[inline(always)]
122 fn from(value: SlotNumber) -> Self {
123 value.0
124 }
125}
126
127impl From<SlotNumber> for u128 {
128 #[inline(always)]
129 fn from(original: SlotNumber) -> Self {
130 u128::from(original.0)
131 }
132}
133
134impl SlotNumber {
135 pub const SIZE: usize = size_of::<u64>();
137 pub const ZERO: Self = Self(0);
139 pub const ONE: Self = Self(1);
141 pub const MAX: Self = Self(u64::MAX);
143
144 #[inline(always)]
146 pub const fn from_bytes(bytes: [u8; const { Self::SIZE }]) -> Self {
147 Self(u64::from_le_bytes(bytes))
148 }
149
150 #[inline(always)]
152 pub const fn to_bytes(self) -> [u8; const { Self::SIZE }] {
153 self.0.to_le_bytes()
154 }
155
156 #[inline(always)]
158 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
159 if let Some(n) = self.0.checked_add(rhs.0) {
160 Some(Self(n))
161 } else {
162 None
163 }
164 }
165
166 #[inline(always)]
168 pub const fn saturating_add(self, rhs: Self) -> Self {
169 Self(self.0.saturating_add(rhs.0))
170 }
171
172 #[inline(always)]
174 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
175 if let Some(n) = self.0.checked_sub(rhs.0) {
176 Some(Self(n))
177 } else {
178 None
179 }
180 }
181
182 #[inline(always)]
184 pub const fn saturating_sub(self, rhs: Self) -> Self {
185 Self(self.0.saturating_sub(rhs.0))
186 }
187}
188
189#[derive(Default, Copy, Clone, Eq, PartialEq, From, Into, AsRef, AsMut, Deref, DerefMut)]
191#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
192pub struct PotKey([u8; const { PotKey::SIZE }]);
193
194impl fmt::Debug for PotKey {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 for byte in self.0 {
197 write!(f, "{byte:02x}")?;
198 }
199 Ok(())
200 }
201}
202
203#[cfg(feature = "serde")]
204#[derive(Serialize, Deserialize)]
205#[serde(transparent)]
206struct PotKeyBinary([u8; const { PotKey::SIZE }]);
207
208#[cfg(feature = "serde")]
209#[derive(Serialize, Deserialize)]
210#[serde(transparent)]
211struct PotKeyHex(#[serde(with = "hex")] [u8; const { PotKey::SIZE }]);
212
213#[cfg(feature = "serde")]
214impl Serialize for PotKey {
215 #[inline]
216 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
217 where
218 S: Serializer,
219 {
220 if serializer.is_human_readable() {
221 PotKeyHex(self.0).serialize(serializer)
222 } else {
223 PotKeyBinary(self.0).serialize(serializer)
224 }
225 }
226}
227
228#[cfg(feature = "serde")]
229impl<'de> Deserialize<'de> for PotKey {
230 #[inline]
231 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
232 where
233 D: Deserializer<'de>,
234 {
235 Ok(Self(if deserializer.is_human_readable() {
236 PotKeyHex::deserialize(deserializer)?.0
237 } else {
238 PotKeyBinary::deserialize(deserializer)?.0
239 }))
240 }
241}
242
243impl fmt::Display for PotKey {
244 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 for byte in self.0 {
246 write!(f, "{byte:02x}")?;
247 }
248 Ok(())
249 }
250}
251
252impl FromStr for PotKey {
253 type Err = hex::FromHexError;
254
255 #[inline]
256 fn from_str(s: &str) -> Result<Self, Self::Err> {
257 let mut key = Self::default();
258 hex::decode_to_slice(s, key.as_mut())?;
259
260 Ok(key)
261 }
262}
263
264impl PotKey {
265 pub const SIZE: usize = 16;
267}
268
269#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, From, Into, AsRef, AsMut, Deref, DerefMut)]
271#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
272pub struct PotSeed([u8; const { 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; const { PotSeed::SIZE }]);
287
288#[cfg(feature = "serde")]
289#[derive(Serialize, Deserialize)]
290#[serde(transparent)]
291struct PotSeedHex(#[serde(with = "hex")] [u8; const { 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(
353 &single_block_hash(&self.0).expect("Less than a single block worth of bytes; qed")
354 [..Self::SIZE],
355 );
356 key
357 }
358}
359
360#[derive(
362 Default,
363 Copy,
364 Clone,
365 Eq,
366 PartialEq,
367 Hash,
368 From,
369 Into,
370 AsRef,
371 AsMut,
372 Deref,
373 DerefMut,
374 TrivialType,
375)]
376#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
377#[repr(C)]
378pub struct PotOutput([u8; const { 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; const { PotOutput::SIZE }]);
393
394#[cfg(feature = "serde")]
395#[derive(Serialize, Deserialize)]
396#[serde(transparent)]
397struct PotOutputHex(#[serde(with = "hex")] [u8; const { 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; const { 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 Blake3Hash::new(
449 single_block_hash(&bytes_to_hash)
450 .expect("Less than a single block worth of bytes; qed"),
451 )
452 }
453
454 #[inline]
456 pub fn seed(&self) -> PotSeed {
457 PotSeed(self.0)
458 }
459
460 #[inline]
462 pub fn seed_with_entropy(&self, entropy: &Blake3Hash) -> PotSeed {
463 let mut bytes_to_hash = [0; const { Blake3Hash::SIZE + Self::SIZE }];
464 bytes_to_hash[..Blake3Hash::SIZE].copy_from_slice(entropy.as_ref());
465 bytes_to_hash[Blake3Hash::SIZE..].copy_from_slice(&self.0);
466 let hash = single_block_hash(&bytes_to_hash)
467 .expect("Less than a single block worth of bytes; qed");
468 let mut seed = PotSeed::default();
469 seed.copy_from_slice(&hash[..Self::SIZE]);
470 seed
471 }
472
473 #[inline]
475 pub fn derive_pot_entropy(&self, solution_chunk: &RecordChunk) -> Blake3Hash {
476 let mut bytes_to_hash = [0; const { RecordChunk::SIZE + Self::SIZE }];
477 bytes_to_hash[..RecordChunk::SIZE].copy_from_slice(solution_chunk.as_ref());
478 bytes_to_hash[RecordChunk::SIZE..].copy_from_slice(&self.0);
479 Blake3Hash::new(
480 single_block_hash(&bytes_to_hash)
481 .expect("Less than a single block worth of bytes; qed"),
482 )
483 }
484
485 #[inline]
487 pub fn shard_membership_entropy(&self) -> ShardMembershipEntropy {
488 ShardMembershipEntropy::new(self.0)
489 }
490
491 #[inline(always)]
493 pub const fn slice_from_repr(value: &[[u8; const { Self::SIZE }]]) -> &[Self] {
494 unsafe { mem::transmute(value) }
496 }
497
498 #[inline(always)]
500 pub const fn repr_from_slice(value: &[Self]) -> &[[u8; const { Self::SIZE }]] {
501 unsafe { mem::transmute(value) }
503 }
504}
505
506#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, TrivialType)]
508#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
509#[repr(C)]
510pub struct PotCheckpoints([PotOutput; PotCheckpoints::NUM_CHECKPOINTS.get() as usize]);
511
512impl PotCheckpoints {
513 pub const SIZE: usize = PotOutput::SIZE * Self::NUM_CHECKPOINTS.get() as usize;
515 pub const NUM_CHECKPOINTS: NonZeroU8 = NonZeroU8::new(8).expect("Not zero; qed");
517
518 #[inline]
520 pub fn output(&self) -> PotOutput {
521 self.0[Self::NUM_CHECKPOINTS.get() as usize - 1]
522 }
523
524 #[inline(always)]
526 pub const fn slice_from_bytes(value: &[[u8; const { Self::SIZE }]]) -> &[Self] {
527 unsafe { mem::transmute(value) }
530 }
531
532 #[inline(always)]
534 pub const fn bytes_from_slice(value: &[Self]) -> &[[u8; const { Self::SIZE }]] {
535 unsafe { mem::transmute(value) }
538 }
539}
540
541#[derive(Debug, Copy, Clone, PartialEq, Eq)]
546#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
547#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
548#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
549pub struct PotParametersChange {
550 pub slot: SlotNumber,
554 pub slot_iterations: NonZeroU32,
556 pub entropy: Blake3Hash,
558}