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 From,
70 Into,
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 backward_checked(start: Self, count: usize) -> Option<Self> {
99 u64::backward_checked(start.0, count).map(Self)
100 }
101}
102
103impl From<SlotNumber> for u128 {
104 #[inline(always)]
105 fn from(original: SlotNumber) -> Self {
106 u128::from(original.0)
107 }
108}
109
110impl SlotNumber {
111 pub const SIZE: usize = size_of::<u64>();
113 pub const ZERO: Self = Self(0);
115 pub const ONE: Self = Self(1);
117 pub const MAX: Self = Self(u64::MAX);
119
120 #[inline(always)]
122 pub const fn new(n: u64) -> Self {
123 Self(n)
124 }
125
126 #[inline(always)]
128 pub const fn as_u64(self) -> u64 {
129 self.0
130 }
131
132 #[inline(always)]
134 pub const fn from_bytes(bytes: [u8; Self::SIZE]) -> Self {
135 Self(u64::from_le_bytes(bytes))
136 }
137
138 #[inline(always)]
140 pub const fn to_bytes(self) -> [u8; Self::SIZE] {
141 self.0.to_le_bytes()
142 }
143
144 #[inline(always)]
146 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
147 if let Some(n) = self.0.checked_add(rhs.0) {
148 Some(Self(n))
149 } else {
150 None
151 }
152 }
153
154 #[inline(always)]
156 pub const fn saturating_add(self, rhs: Self) -> Self {
157 Self(self.0.saturating_add(rhs.0))
158 }
159
160 #[inline(always)]
162 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
163 if let Some(n) = self.0.checked_sub(rhs.0) {
164 Some(Self(n))
165 } else {
166 None
167 }
168 }
169
170 #[inline(always)]
172 pub const fn saturating_sub(self, rhs: Self) -> Self {
173 Self(self.0.saturating_sub(rhs.0))
174 }
175}
176
177#[derive(Default, Copy, Clone, Eq, PartialEq, From, Into, AsRef, AsMut, Deref, DerefMut)]
179#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
180pub struct PotKey([u8; PotKey::SIZE]);
181
182impl fmt::Debug for PotKey {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 for byte in self.0 {
185 write!(f, "{byte:02x}")?;
186 }
187 Ok(())
188 }
189}
190
191#[cfg(feature = "serde")]
192#[derive(Serialize, Deserialize)]
193#[serde(transparent)]
194struct PotKeyBinary([u8; PotKey::SIZE]);
195
196#[cfg(feature = "serde")]
197#[derive(Serialize, Deserialize)]
198#[serde(transparent)]
199struct PotKeyHex(#[serde(with = "hex")] [u8; PotKey::SIZE]);
200
201#[cfg(feature = "serde")]
202impl Serialize for PotKey {
203 #[inline]
204 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
205 where
206 S: Serializer,
207 {
208 if serializer.is_human_readable() {
209 PotKeyHex(self.0).serialize(serializer)
210 } else {
211 PotKeyBinary(self.0).serialize(serializer)
212 }
213 }
214}
215
216#[cfg(feature = "serde")]
217impl<'de> Deserialize<'de> for PotKey {
218 #[inline]
219 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
220 where
221 D: Deserializer<'de>,
222 {
223 Ok(Self(if deserializer.is_human_readable() {
224 PotKeyHex::deserialize(deserializer)?.0
225 } else {
226 PotKeyBinary::deserialize(deserializer)?.0
227 }))
228 }
229}
230
231impl fmt::Display for PotKey {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 for byte in self.0 {
234 write!(f, "{byte:02x}")?;
235 }
236 Ok(())
237 }
238}
239
240impl FromStr for PotKey {
241 type Err = hex::FromHexError;
242
243 #[inline]
244 fn from_str(s: &str) -> Result<Self, Self::Err> {
245 let mut key = Self::default();
246 hex::decode_to_slice(s, key.as_mut())?;
247
248 Ok(key)
249 }
250}
251
252impl PotKey {
253 pub const SIZE: usize = 16;
255}
256
257#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, From, Into, AsRef, AsMut, Deref, DerefMut)]
259#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
260pub struct PotSeed([u8; PotSeed::SIZE]);
261
262impl fmt::Debug for PotSeed {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 for byte in self.0 {
265 write!(f, "{byte:02x}")?;
266 }
267 Ok(())
268 }
269}
270
271#[cfg(feature = "serde")]
272#[derive(Serialize, Deserialize)]
273#[serde(transparent)]
274struct PotSeedBinary([u8; PotSeed::SIZE]);
275
276#[cfg(feature = "serde")]
277#[derive(Serialize, Deserialize)]
278#[serde(transparent)]
279struct PotSeedHex(#[serde(with = "hex")] [u8; PotSeed::SIZE]);
280
281#[cfg(feature = "serde")]
282impl Serialize for PotSeed {
283 #[inline]
284 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
285 where
286 S: Serializer,
287 {
288 if serializer.is_human_readable() {
289 PotSeedHex(self.0).serialize(serializer)
290 } else {
291 PotSeedBinary(self.0).serialize(serializer)
292 }
293 }
294}
295
296#[cfg(feature = "serde")]
297impl<'de> Deserialize<'de> for PotSeed {
298 #[inline]
299 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
300 where
301 D: Deserializer<'de>,
302 {
303 Ok(Self(if deserializer.is_human_readable() {
304 PotSeedHex::deserialize(deserializer)?.0
305 } else {
306 PotSeedBinary::deserialize(deserializer)?.0
307 }))
308 }
309}
310
311impl fmt::Display for PotSeed {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 for byte in self.0 {
314 write!(f, "{byte:02x}")?;
315 }
316 Ok(())
317 }
318}
319
320impl PotSeed {
321 pub const SIZE: usize = 16;
323
324 #[inline]
326 pub fn from_genesis(genesis_block_root: &BlockRoot, external_entropy: &[u8]) -> Self {
327 let mut hasher = blake3::Hasher::new();
328 hasher.update(genesis_block_root.as_ref());
329 hasher.update(external_entropy);
330 let hash = hasher.finalize();
331 let mut seed = Self::default();
332 seed.copy_from_slice(&hash.as_bytes()[..Self::SIZE]);
333 seed
334 }
335
336 #[inline]
338 pub fn key(&self) -> PotKey {
339 let mut key = PotKey::default();
340 key.copy_from_slice(
341 &single_block_hash(&self.0).expect("Less than a single block worth of bytes; qed")
342 [..Self::SIZE],
343 );
344 key
345 }
346}
347
348#[derive(
350 Default,
351 Copy,
352 Clone,
353 Eq,
354 PartialEq,
355 Hash,
356 From,
357 Into,
358 AsRef,
359 AsMut,
360 Deref,
361 DerefMut,
362 TrivialType,
363)]
364#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
365#[repr(C)]
366pub struct PotOutput([u8; PotOutput::SIZE]);
367
368impl fmt::Debug for PotOutput {
369 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370 for byte in self.0 {
371 write!(f, "{byte:02x}")?;
372 }
373 Ok(())
374 }
375}
376
377#[cfg(feature = "serde")]
378#[derive(Serialize, Deserialize)]
379#[serde(transparent)]
380struct PotOutputBinary([u8; PotOutput::SIZE]);
381
382#[cfg(feature = "serde")]
383#[derive(Serialize, Deserialize)]
384#[serde(transparent)]
385struct PotOutputHex(#[serde(with = "hex")] [u8; PotOutput::SIZE]);
386
387#[cfg(feature = "serde")]
388impl Serialize for PotOutput {
389 #[inline]
390 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
391 where
392 S: Serializer,
393 {
394 if serializer.is_human_readable() {
395 PotOutputHex(self.0).serialize(serializer)
396 } else {
397 PotOutputBinary(self.0).serialize(serializer)
398 }
399 }
400}
401
402#[cfg(feature = "serde")]
403impl<'de> Deserialize<'de> for PotOutput {
404 #[inline]
405 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
406 where
407 D: Deserializer<'de>,
408 {
409 Ok(Self(if deserializer.is_human_readable() {
410 PotOutputHex::deserialize(deserializer)?.0
411 } else {
412 PotOutputBinary::deserialize(deserializer)?.0
413 }))
414 }
415}
416
417impl fmt::Display for PotOutput {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 for byte in self.0 {
420 write!(f, "{byte:02x}")?;
421 }
422 Ok(())
423 }
424}
425
426impl PotOutput {
427 pub const SIZE: usize = 16;
429
430 #[inline]
432 pub fn derive_global_challenge(&self, slot: SlotNumber) -> Blake3Hash {
433 let mut bytes_to_hash = [0; Self::SIZE + SlotNumber::SIZE];
434 bytes_to_hash[..Self::SIZE].copy_from_slice(&self.0);
435 bytes_to_hash[Self::SIZE..].copy_from_slice(&slot.to_bytes());
436 Blake3Hash::new(
437 single_block_hash(&bytes_to_hash)
438 .expect("Less than a single block worth of bytes; qed"),
439 )
440 }
441
442 #[inline]
444 pub fn seed(&self) -> PotSeed {
445 PotSeed(self.0)
446 }
447
448 #[inline]
450 pub fn seed_with_entropy(&self, entropy: &Blake3Hash) -> PotSeed {
451 let mut bytes_to_hash = [0; Blake3Hash::SIZE + Self::SIZE];
452 bytes_to_hash[..Blake3Hash::SIZE].copy_from_slice(entropy.as_ref());
453 bytes_to_hash[Blake3Hash::SIZE..].copy_from_slice(&self.0);
454 let hash = single_block_hash(&bytes_to_hash)
455 .expect("Less than a single block worth of bytes; qed");
456 let mut seed = PotSeed::default();
457 seed.copy_from_slice(&hash[..Self::SIZE]);
458 seed
459 }
460
461 #[inline]
463 pub fn derive_pot_entropy(&self, solution_chunk: &RecordChunk) -> Blake3Hash {
464 let mut bytes_to_hash = [0; RecordChunk::SIZE + Self::SIZE];
465 bytes_to_hash[..RecordChunk::SIZE].copy_from_slice(solution_chunk.as_ref());
466 bytes_to_hash[RecordChunk::SIZE..].copy_from_slice(&self.0);
467 Blake3Hash::new(
468 single_block_hash(&bytes_to_hash)
469 .expect("Less than a single block worth of bytes; qed"),
470 )
471 }
472
473 #[inline]
475 pub fn shard_membership_entropy(&self) -> ShardMembershipEntropy {
476 ShardMembershipEntropy::new(self.0)
477 }
478
479 #[inline(always)]
481 pub const fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
482 unsafe { mem::transmute(value) }
484 }
485
486 #[inline(always)]
488 pub const fn repr_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
489 unsafe { mem::transmute(value) }
491 }
492}
493
494#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut, TrivialType)]
496#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
497#[repr(C)]
498pub struct PotCheckpoints([PotOutput; PotCheckpoints::NUM_CHECKPOINTS.get() as usize]);
499
500impl PotCheckpoints {
501 pub const SIZE: usize = PotOutput::SIZE * Self::NUM_CHECKPOINTS.get() as usize;
503 pub const NUM_CHECKPOINTS: NonZeroU8 = NonZeroU8::new(8).expect("Not zero; qed");
505
506 #[inline]
508 pub fn output(&self) -> PotOutput {
509 self.0[Self::NUM_CHECKPOINTS.get() as usize - 1]
510 }
511
512 #[inline(always)]
514 pub const fn slice_from_bytes(value: &[[u8; Self::SIZE]]) -> &[Self] {
515 unsafe { mem::transmute(value) }
518 }
519
520 #[inline(always)]
522 pub const fn bytes_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
523 unsafe { mem::transmute(value) }
526 }
527}
528
529#[derive(Debug, Copy, Clone, PartialEq, Eq)]
534#[cfg_attr(feature = "scale-codec", derive(Encode, Decode, MaxEncodedLen))]
535#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
536#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
537pub struct PotParametersChange {
538 pub slot: SlotNumber,
542 pub slot_iterations: NonZeroU32,
544 pub entropy: Blake3Hash,
546}