1use crate::{Epochable, Viewable};
38use bytes::{Buf, BufMut};
39use commonware_codec::{varint::UInt, EncodeSize, Error, Read, ReadExt, Write};
40#[cfg(not(target_arch = "wasm32"))]
41use commonware_runtime::telemetry::traces::TracedExt;
42use commonware_utils::sequence::U64;
43use core::{
44 fmt::{self, Display, Formatter},
45 marker::PhantomData,
46 num::NonZeroU64,
47};
48
49#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
54#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
55pub struct Epoch(u64);
56
57impl Epoch {
58 pub const fn zero() -> Self {
60 Self(0)
61 }
62
63 pub const fn new(value: u64) -> Self {
65 Self(value)
66 }
67
68 pub const fn get(self) -> u64 {
70 self.0
71 }
72
73 pub const fn is_zero(self) -> bool {
75 self.0 == 0
76 }
77
78 pub const fn next(self) -> Self {
85 Self(self.0.checked_add(1).expect("epoch overflow"))
86 }
87
88 pub fn previous(self) -> Option<Self> {
94 self.0.checked_sub(1).map(Self)
95 }
96
97 pub const fn saturating_add(self, delta: EpochDelta) -> Self {
99 Self(self.0.saturating_add(delta.0))
100 }
101
102 pub fn checked_sub(self, delta: EpochDelta) -> Option<Self> {
104 self.0.checked_sub(delta.0).map(Self)
105 }
106
107 pub const fn saturating_sub(self, delta: EpochDelta) -> Self {
109 Self(self.0.saturating_sub(delta.0))
110 }
111}
112
113impl Display for Epoch {
114 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
115 write!(f, "{}", self.0)
116 }
117}
118
119impl Read for Epoch {
120 type Cfg = ();
121
122 fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, Error> {
123 let value: u64 = UInt::read(buf)?.into();
124 Ok(Self(value))
125 }
126}
127
128impl Write for Epoch {
129 fn write(&self, buf: &mut impl BufMut) {
130 UInt(self.0).write(buf);
131 }
132}
133
134impl EncodeSize for Epoch {
135 fn encode_size(&self) -> usize {
136 UInt(self.0).encode_size()
137 }
138}
139
140impl From<Epoch> for U64 {
141 fn from(epoch: Epoch) -> Self {
142 Self::from(epoch.get())
143 }
144}
145
146#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
150#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
151pub struct Height(u64);
152
153impl Height {
154 pub const fn zero() -> Self {
156 Self(0)
157 }
158
159 pub const fn new(value: u64) -> Self {
161 Self(value)
162 }
163
164 pub const fn get(self) -> u64 {
166 self.0
167 }
168
169 pub const fn is_zero(self) -> bool {
171 self.0 == 0
172 }
173
174 pub const fn next(self) -> Self {
181 Self(self.0.checked_add(1).expect("height overflow"))
182 }
183
184 pub fn previous(self) -> Option<Self> {
190 self.0.checked_sub(1).map(Self)
191 }
192
193 pub const fn saturating_add(self, delta: HeightDelta) -> Self {
195 Self(self.0.saturating_add(delta.0))
196 }
197
198 pub const fn saturating_sub(self, delta: HeightDelta) -> Self {
200 Self(self.0.saturating_sub(delta.0))
201 }
202
203 pub fn delta_from(self, other: Self) -> Option<HeightDelta> {
205 self.0.checked_sub(other.0).map(HeightDelta::new)
206 }
207
208 pub const fn range(start: Self, end: Self) -> HeightRange {
212 HeightRange {
213 inner: start.get()..end.get(),
214 }
215 }
216}
217
218impl Display for Height {
219 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
220 write!(f, "{}", self.0)
221 }
222}
223
224impl Read for Height {
225 type Cfg = ();
226
227 fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, Error> {
228 let value: u64 = UInt::read(buf)?.into();
229 Ok(Self(value))
230 }
231}
232
233impl Write for Height {
234 fn write(&self, buf: &mut impl BufMut) {
235 UInt(self.0).write(buf);
236 }
237}
238
239impl EncodeSize for Height {
240 fn encode_size(&self) -> usize {
241 UInt(self.0).encode_size()
242 }
243}
244
245impl From<Height> for U64 {
246 fn from(height: Height) -> Self {
247 Self::from(height.get())
248 }
249}
250
251#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
256#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
257pub struct View(u64);
258
259impl View {
260 pub const fn zero() -> Self {
262 Self(0)
263 }
264
265 pub const fn new(value: u64) -> Self {
267 Self(value)
268 }
269
270 pub const fn get(self) -> u64 {
272 self.0
273 }
274
275 pub const fn is_zero(self) -> bool {
277 self.0 == 0
278 }
279
280 pub const fn next(self) -> Self {
287 Self(self.0.checked_add(1).expect("view overflow"))
288 }
289
290 pub fn previous(self) -> Option<Self> {
296 self.0.checked_sub(1).map(Self)
297 }
298
299 pub const fn saturating_add(self, delta: ViewDelta) -> Self {
301 Self(self.0.saturating_add(delta.0))
302 }
303
304 pub const fn saturating_sub(self, delta: ViewDelta) -> Self {
306 Self(self.0.saturating_sub(delta.0))
307 }
308
309 pub const fn range(start: Self, end: Self) -> ViewRange {
313 ViewRange {
314 inner: start.get()..end.get(),
315 }
316 }
317}
318
319impl Display for View {
320 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
321 write!(f, "{}", self.0)
322 }
323}
324
325#[cfg(not(target_arch = "wasm32"))]
326impl TracedExt for Epoch {
327 fn traced(self) -> i64 {
328 self.0.traced()
329 }
330}
331
332#[cfg(not(target_arch = "wasm32"))]
333impl TracedExt for Height {
334 fn traced(self) -> i64 {
335 self.0.traced()
336 }
337}
338
339#[cfg(not(target_arch = "wasm32"))]
340impl TracedExt for View {
341 fn traced(self) -> i64 {
342 self.0.traced()
343 }
344}
345
346impl Read for View {
347 type Cfg = ();
348
349 fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, Error> {
350 let value: u64 = UInt::read(buf)?.into();
351 Ok(Self(value))
352 }
353}
354
355impl Write for View {
356 fn write(&self, buf: &mut impl BufMut) {
357 UInt(self.0).write(buf);
358 }
359}
360
361impl EncodeSize for View {
362 fn encode_size(&self) -> usize {
363 UInt(self.0).encode_size()
364 }
365}
366
367impl From<View> for U64 {
368 fn from(view: View) -> Self {
369 Self::from(view.get())
370 }
371}
372
373#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
381pub struct Delta<T>(u64, PhantomData<T>);
382
383impl<T> Delta<T> {
384 pub const fn zero() -> Self {
386 Self(0, PhantomData)
387 }
388
389 pub const fn new(value: u64) -> Self {
391 Self(value, PhantomData)
392 }
393
394 pub const fn get(self) -> u64 {
396 self.0
397 }
398
399 pub const fn is_zero(self) -> bool {
401 self.0 == 0
402 }
403}
404
405impl<T> Display for Delta<T> {
406 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
407 write!(f, "{}", self.0)
408 }
409}
410
411pub type EpochDelta = Delta<Epoch>;
416
417pub type HeightDelta = Delta<Height>;
422
423pub type ViewDelta = Delta<View>;
428
429#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
434#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
435pub struct Round {
436 epoch: Epoch,
437 view: View,
438}
439
440impl Round {
441 pub const fn new(epoch: Epoch, view: View) -> Self {
443 Self { epoch, view }
444 }
445
446 pub const fn zero() -> Self {
448 Self::new(Epoch::zero(), View::zero())
449 }
450
451 pub const fn epoch(self) -> Epoch {
453 self.epoch
454 }
455
456 pub const fn view(self) -> View {
458 self.view
459 }
460}
461
462impl Epochable for Round {
463 fn epoch(&self) -> Epoch {
464 self.epoch
465 }
466}
467
468impl Viewable for Round {
469 fn view(&self) -> View {
470 self.view
471 }
472}
473
474impl From<(Epoch, View)> for Round {
475 fn from((epoch, view): (Epoch, View)) -> Self {
476 Self { epoch, view }
477 }
478}
479
480impl From<Round> for (Epoch, View) {
481 fn from(round: Round) -> Self {
482 (round.epoch, round.view)
483 }
484}
485
486#[derive(Clone, Copy, Debug, PartialEq, Eq)]
490pub enum EpochPhase {
491 Early,
493 Midpoint,
495 Late,
497}
498
499#[derive(Clone, Copy, Debug, PartialEq, Eq)]
501pub struct EpochInfo {
502 epoch: Epoch,
503 height: Height,
504 first: Height,
505 last: Height,
506}
507
508impl EpochInfo {
509 pub const fn new(epoch: Epoch, height: Height, first: Height, last: Height) -> Self {
511 Self {
512 epoch,
513 height,
514 first,
515 last,
516 }
517 }
518
519 pub const fn epoch(&self) -> Epoch {
521 self.epoch
522 }
523
524 pub const fn height(&self) -> Height {
526 self.height
527 }
528
529 pub const fn first(&self) -> Height {
531 self.first
532 }
533
534 pub const fn last(&self) -> Height {
536 self.last
537 }
538
539 pub const fn length(&self) -> HeightDelta {
541 HeightDelta::new(self.last.get() - self.first.get() + 1)
542 }
543
544 pub const fn relative(&self) -> Height {
546 Height::new(self.height.get() - self.first.get())
547 }
548
549 pub const fn phase(&self) -> EpochPhase {
551 let relative = self.relative().get();
552 let midpoint = self.length().get() / 2;
553
554 if relative < midpoint {
555 EpochPhase::Early
556 } else if relative == midpoint {
557 EpochPhase::Midpoint
558 } else {
559 EpochPhase::Late
560 }
561 }
562}
563
564pub trait Epocher: Clone + Send + Sync + 'static {
566 fn containing(&self, height: Height) -> Option<EpochInfo>;
570
571 fn first(&self, epoch: Epoch) -> Option<Height>;
575
576 fn last(&self, epoch: Epoch) -> Option<Height>;
580}
581
582#[derive(Clone, Debug, PartialEq, Eq)]
584pub struct FixedEpocher(u64);
585
586impl FixedEpocher {
587 pub const fn new(length: NonZeroU64) -> Self {
596 Self(length.get())
597 }
598
599 fn bounds(&self, epoch: Epoch) -> Option<(Height, Height)> {
602 let first = epoch.get().checked_mul(self.0)?;
603 let last = first.checked_add(self.0 - 1)?;
604 Some((Height::new(first), Height::new(last)))
605 }
606}
607
608impl Epocher for FixedEpocher {
609 fn containing(&self, height: Height) -> Option<EpochInfo> {
610 let epoch = Epoch::new(height.get() / self.0);
611 let (first, last) = self.bounds(epoch)?;
612 Some(EpochInfo::new(epoch, height, first, last))
613 }
614
615 fn first(&self, epoch: Epoch) -> Option<Height> {
616 self.bounds(epoch).map(|(first, _)| first)
617 }
618
619 fn last(&self, epoch: Epoch) -> Option<Height> {
620 self.bounds(epoch).map(|(_, last)| last)
621 }
622}
623
624impl Read for Round {
625 type Cfg = ();
626
627 fn read_cfg(buf: &mut impl Buf, _cfg: &Self::Cfg) -> Result<Self, Error> {
628 Ok(Self {
629 epoch: Epoch::read(buf)?,
630 view: View::read(buf)?,
631 })
632 }
633}
634
635impl Write for Round {
636 fn write(&self, buf: &mut impl BufMut) {
637 self.epoch.write(buf);
638 self.view.write(buf);
639 }
640}
641
642impl EncodeSize for Round {
643 fn encode_size(&self) -> usize {
644 self.epoch.encode_size() + self.view.encode_size()
645 }
646}
647
648impl Display for Round {
649 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
650 write!(f, "({}, {})", self.epoch, self.view)
651 }
652}
653
654pub struct ViewRange {
658 inner: std::ops::Range<u64>,
659}
660
661impl Iterator for ViewRange {
662 type Item = View;
663
664 fn next(&mut self) -> Option<Self::Item> {
665 self.inner.next().map(View::new)
666 }
667
668 fn size_hint(&self) -> (usize, Option<usize>) {
669 self.inner.size_hint()
670 }
671}
672
673impl DoubleEndedIterator for ViewRange {
674 fn next_back(&mut self) -> Option<Self::Item> {
675 self.inner.next_back().map(View::new)
676 }
677}
678
679impl ExactSizeIterator for ViewRange {
680 fn len(&self) -> usize {
681 self.size_hint().0
682 }
683}
684
685pub struct HeightRange {
689 inner: std::ops::Range<u64>,
690}
691
692impl Iterator for HeightRange {
693 type Item = Height;
694
695 fn next(&mut self) -> Option<Self::Item> {
696 self.inner.next().map(Height::new)
697 }
698
699 fn size_hint(&self) -> (usize, Option<usize>) {
700 self.inner.size_hint()
701 }
702}
703
704impl DoubleEndedIterator for HeightRange {
705 fn next_back(&mut self) -> Option<Self::Item> {
706 self.inner.next_back().map(Height::new)
707 }
708}
709
710impl ExactSizeIterator for HeightRange {
711 fn len(&self) -> usize {
712 self.size_hint().0
713 }
714}
715
716pub use commonware_utils::Participant;
718
719commonware_macros::stability_scope!(ALPHA {
720 pub mod coding {
721 use commonware_codec::{Encode, FixedArray, FixedSize, Read, ReadExt, Write};
724 use commonware_coding::Config as CodingConfig;
725 use commonware_cryptography::Digest;
726 use commonware_math::algebra::Random;
727 use commonware_utils::{Array, Span, NZU16};
728 use core::{
729 num::NonZeroU16,
730 ops::{Deref, Range},
731 };
732 use rand_core::CryptoRng;
733
734 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, FixedArray)]
742 pub struct Commitment([u8; Self::SIZE]);
743
744 impl Commitment {
745 const DIGEST_SIZE: usize = 32;
746 const BLOCK_DIGEST_OFFSET: usize = 0;
747 const CODING_ROOT_OFFSET: usize = Self::BLOCK_DIGEST_OFFSET + Self::DIGEST_SIZE;
748 const CONTEXT_DIGEST_OFFSET: usize = Self::CODING_ROOT_OFFSET + Self::DIGEST_SIZE;
749 const CONFIG_OFFSET: usize = Self::CONTEXT_DIGEST_OFFSET + Self::DIGEST_SIZE;
750
751 pub fn config(&self) -> CodingConfig {
753 let mut buf = &self.0[Self::CONFIG_OFFSET..];
754 CodingConfig::read(&mut buf).expect("Commitment always contains a valid config")
755 }
756
757 pub fn block<D: Digest>(&self) -> D {
763 self.take(Self::BLOCK_DIGEST_OFFSET..Self::BLOCK_DIGEST_OFFSET + D::SIZE)
764 }
765
766 pub fn root<D: Digest>(&self) -> D {
772 self.take(Self::CODING_ROOT_OFFSET..Self::CODING_ROOT_OFFSET + D::SIZE)
773 }
774
775 pub fn context<D: Digest>(&self) -> D {
781 self.take(Self::CONTEXT_DIGEST_OFFSET..Self::CONTEXT_DIGEST_OFFSET + D::SIZE)
782 }
783
784 fn take<D: Digest>(&self, range: Range<usize>) -> D {
790 const {
791 assert!(
792 D::SIZE <= 32,
793 "Cannot extract Digest with size > 32 from Commitment"
794 );
795 }
796
797 D::read(&mut self.0[range].as_ref())
798 .expect("Commitment always contains a valid digest")
799 }
800 }
801
802 impl Random for Commitment {
803 fn random(mut rng: impl CryptoRng) -> Self {
804 let mut buf = [0u8; Self::SIZE];
805 rng.fill_bytes(&mut buf[..Self::CONFIG_OFFSET]);
806
807 let one = NZU16!(1);
808 let shards = rng.next_u32();
809 let config = CodingConfig {
810 minimum_shards: NonZeroU16::new(shards as u16).unwrap_or(one),
811 extra_shards: NonZeroU16::new((shards >> 16) as u16).unwrap_or(one),
812 };
813 let mut cfg_buf = &mut buf[Self::CONFIG_OFFSET..];
814 config.write(&mut cfg_buf);
815
816 Self(buf)
817 }
818 }
819
820 impl Digest for Commitment {
821 const EMPTY: Self = Self([0u8; Self::SIZE]);
822 }
823
824 impl Write for Commitment {
825 fn write(&self, buf: &mut impl bytes::BufMut) {
826 buf.put_slice(&self.0);
827 }
828 }
829
830 impl FixedSize for Commitment {
831 const SIZE: usize = Self::CONFIG_OFFSET + CodingConfig::SIZE;
832 }
833
834 impl Read for Commitment {
835 type Cfg = ();
836
837 fn read_cfg(
838 buf: &mut impl bytes::Buf,
839 _cfg: &Self::Cfg,
840 ) -> Result<Self, commonware_codec::Error> {
841 if buf.remaining() < Self::SIZE {
842 return Err(commonware_codec::Error::EndOfBuffer);
843 }
844 let mut arr = [0u8; Self::SIZE];
845 buf.copy_to_slice(&mut arr);
846
847 let mut cfg_buf = &arr[Self::CONFIG_OFFSET..];
850 CodingConfig::read(&mut cfg_buf).map_err(|_| {
851 commonware_codec::Error::Invalid("Commitment", "invalid embedded CodingConfig")
852 })?;
853
854 Ok(Self(arr))
855 }
856 }
857
858 impl AsRef<[u8]> for Commitment {
859 fn as_ref(&self) -> &[u8] {
860 &self.0
861 }
862 }
863
864 impl Deref for Commitment {
865 type Target = [u8];
866
867 fn deref(&self) -> &Self::Target {
868 &self.0
869 }
870 }
871
872 impl core::fmt::Display for Commitment {
873 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
874 write!(f, "{}", commonware_formatting::Hex(self.as_ref()))
875 }
876 }
877
878 impl core::fmt::Debug for Commitment {
879 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
880 write!(f, "{}", commonware_formatting::Hex(self.as_ref()))
881 }
882 }
883
884 impl Default for Commitment {
885 fn default() -> Self {
886 Self([0u8; Self::SIZE])
887 }
888 }
889
890 impl<D1: Digest, D2: Digest, D3: Digest> From<(D1, D2, D3, CodingConfig)> for Commitment {
891 fn from(
892 (digest, commitment, context_digest, config): (D1, D2, D3, CodingConfig),
893 ) -> Self {
894 const {
895 assert!(
896 D1::SIZE <= Self::DIGEST_SIZE,
897 "Cannot create Commitment from Digest with size > Self::DIGEST_SIZE"
898 );
899 assert!(
900 D2::SIZE <= Self::DIGEST_SIZE,
901 "Cannot create Commitment from Digest with size > Self::DIGEST_SIZE"
902 );
903 assert!(
904 D3::SIZE <= Self::DIGEST_SIZE,
905 "Cannot create Commitment from Digest with size > Self::DIGEST_SIZE"
906 );
907 }
908
909 let mut buf = [0u8; Self::SIZE];
910 buf[..D1::SIZE].copy_from_slice(&digest);
911 buf[Self::CODING_ROOT_OFFSET..Self::CODING_ROOT_OFFSET + D2::SIZE]
912 .copy_from_slice(&commitment);
913 buf[Self::CONTEXT_DIGEST_OFFSET..Self::CONTEXT_DIGEST_OFFSET + D3::SIZE]
914 .copy_from_slice(&context_digest);
915 buf[Self::CONFIG_OFFSET..].copy_from_slice(&config.encode());
916 Self(buf)
917 }
918 }
919
920 impl Span for Commitment {}
921
922 impl Array for Commitment {}
923
924 #[cfg(feature = "arbitrary")]
925 impl arbitrary::Arbitrary<'_> for Commitment {
926 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
927 let config = CodingConfig::arbitrary(u)?;
928 let mut buf = [0u8; Self::SIZE];
929 buf[..96].copy_from_slice(u.bytes(96)?);
930 buf[96..].copy_from_slice(&config.encode());
931 Ok(Self(buf))
932 }
933 }
934 }
935});
936
937#[cfg(test)]
938mod tests {
939 use super::*;
940 use crate::types::coding::Commitment;
941 use commonware_codec::{DecodeExt, Encode, EncodeSize, FixedSize};
942 use commonware_coding::Config as CodingConfig;
943 use commonware_math::algebra::Random;
944 use commonware_utils::{test_rng, Array, Span, NZU16, NZU64};
945 use std::ops::Deref;
946
947 #[test]
948 fn test_epoch_constructors() {
949 assert_eq!(Epoch::zero().get(), 0);
950 assert_eq!(Epoch::new(42).get(), 42);
951 assert_eq!(Epoch::default().get(), 0);
952 }
953
954 #[test]
955 fn test_epoch_is_zero() {
956 assert!(Epoch::zero().is_zero());
957 assert!(Epoch::new(0).is_zero());
958 assert!(!Epoch::new(1).is_zero());
959 assert!(!Epoch::new(100).is_zero());
960 }
961
962 #[test]
963 fn test_epoch_next() {
964 assert_eq!(Epoch::zero().next().get(), 1);
965 assert_eq!(Epoch::new(5).next().get(), 6);
966 assert_eq!(Epoch::new(999).next().get(), 1000);
967 }
968
969 #[test]
970 #[should_panic(expected = "epoch overflow")]
971 fn test_epoch_next_overflow() {
972 Epoch::new(u64::MAX).next();
973 }
974
975 #[test]
976 fn test_epoch_previous() {
977 assert_eq!(Epoch::zero().previous(), None);
978 assert_eq!(Epoch::new(1).previous(), Some(Epoch::zero()));
979 assert_eq!(Epoch::new(5).previous(), Some(Epoch::new(4)));
980 assert_eq!(Epoch::new(1000).previous(), Some(Epoch::new(999)));
981 }
982
983 #[test]
984 fn test_epoch_saturating_add() {
985 assert_eq!(Epoch::zero().saturating_add(EpochDelta::new(5)).get(), 5);
986 assert_eq!(Epoch::new(10).saturating_add(EpochDelta::new(20)).get(), 30);
987 assert_eq!(
988 Epoch::new(u64::MAX)
989 .saturating_add(EpochDelta::new(1))
990 .get(),
991 u64::MAX
992 );
993 assert_eq!(
994 Epoch::new(u64::MAX - 5)
995 .saturating_add(EpochDelta::new(10))
996 .get(),
997 u64::MAX
998 );
999 }
1000
1001 #[test]
1002 fn test_epoch_checked_sub() {
1003 assert_eq!(
1004 Epoch::new(10).checked_sub(EpochDelta::new(5)),
1005 Some(Epoch::new(5))
1006 );
1007 assert_eq!(
1008 Epoch::new(5).checked_sub(EpochDelta::new(5)),
1009 Some(Epoch::zero())
1010 );
1011 assert_eq!(Epoch::new(5).checked_sub(EpochDelta::new(10)), None);
1012 assert_eq!(Epoch::zero().checked_sub(EpochDelta::new(1)), None);
1013 }
1014
1015 #[test]
1016 fn test_epoch_saturating_sub() {
1017 assert_eq!(Epoch::new(10).saturating_sub(EpochDelta::new(5)).get(), 5);
1018 assert_eq!(Epoch::new(5).saturating_sub(EpochDelta::new(5)).get(), 0);
1019 assert_eq!(Epoch::new(5).saturating_sub(EpochDelta::new(10)).get(), 0);
1020 assert_eq!(Epoch::zero().saturating_sub(EpochDelta::new(100)).get(), 0);
1021 }
1022
1023 #[test]
1024 fn test_epoch_display() {
1025 assert_eq!(format!("{}", Epoch::zero()), "0");
1026 assert_eq!(format!("{}", Epoch::new(42)), "42");
1027 assert_eq!(format!("{}", Epoch::new(1000)), "1000");
1028 }
1029
1030 #[test]
1031 fn test_epoch_ordering() {
1032 assert!(Epoch::zero() < Epoch::new(1));
1033 assert!(Epoch::new(5) < Epoch::new(10));
1034 assert!(Epoch::new(10) > Epoch::new(5));
1035 assert_eq!(Epoch::new(42), Epoch::new(42));
1036 }
1037
1038 #[test]
1039 fn test_epoch_encode_decode() {
1040 let cases = vec![0u64, 1, 127, 128, 255, 256, u64::MAX];
1041 for value in cases {
1042 let epoch = Epoch::new(value);
1043 let encoded = epoch.encode();
1044 assert_eq!(encoded.len(), epoch.encode_size());
1045 let decoded = Epoch::decode(encoded).unwrap();
1046 assert_eq!(epoch, decoded);
1047 }
1048 }
1049
1050 #[test]
1051 fn test_height_constructors() {
1052 assert_eq!(Height::zero().get(), 0);
1053 assert_eq!(Height::new(42).get(), 42);
1054 assert_eq!(Height::new(100).get(), 100);
1055 assert_eq!(Height::default().get(), 0);
1056 }
1057
1058 #[test]
1059 fn test_height_is_zero() {
1060 assert!(Height::zero().is_zero());
1061 assert!(Height::new(0).is_zero());
1062 assert!(!Height::new(1).is_zero());
1063 assert!(!Height::new(100).is_zero());
1064 }
1065
1066 #[test]
1067 fn test_height_next() {
1068 assert_eq!(Height::zero().next().get(), 1);
1069 assert_eq!(Height::new(5).next().get(), 6);
1070 assert_eq!(Height::new(999).next().get(), 1000);
1071 }
1072
1073 #[test]
1074 #[should_panic(expected = "height overflow")]
1075 fn test_height_next_overflow() {
1076 Height::new(u64::MAX).next();
1077 }
1078
1079 #[test]
1080 fn test_height_previous() {
1081 assert_eq!(Height::zero().previous(), None);
1082 assert_eq!(Height::new(1).previous(), Some(Height::zero()));
1083 assert_eq!(Height::new(5).previous(), Some(Height::new(4)));
1084 assert_eq!(Height::new(1000).previous(), Some(Height::new(999)));
1085 }
1086
1087 #[test]
1088 fn test_height_saturating_add() {
1089 let delta5 = HeightDelta::new(5);
1090 let delta100 = HeightDelta::new(100);
1091 assert_eq!(Height::zero().saturating_add(delta5).get(), 5);
1092 assert_eq!(Height::new(10).saturating_add(delta100).get(), 110);
1093 assert_eq!(
1094 Height::new(u64::MAX)
1095 .saturating_add(HeightDelta::new(1))
1096 .get(),
1097 u64::MAX
1098 );
1099 }
1100
1101 #[test]
1102 fn test_height_saturating_sub() {
1103 let delta5 = HeightDelta::new(5);
1104 let delta100 = HeightDelta::new(100);
1105 assert_eq!(Height::new(10).saturating_sub(delta5).get(), 5);
1106 assert_eq!(Height::new(5).saturating_sub(delta5).get(), 0);
1107 assert_eq!(Height::new(5).saturating_sub(delta100).get(), 0);
1108 assert_eq!(Height::zero().saturating_sub(delta100).get(), 0);
1109 }
1110
1111 #[test]
1112 fn test_height_display() {
1113 assert_eq!(format!("{}", Height::zero()), "0");
1114 assert_eq!(format!("{}", Height::new(42)), "42");
1115 assert_eq!(format!("{}", Height::new(1000)), "1000");
1116 }
1117
1118 #[test]
1119 fn test_height_ordering() {
1120 assert!(Height::zero() < Height::new(1));
1121 assert!(Height::new(5) < Height::new(10));
1122 assert!(Height::new(10) > Height::new(5));
1123 assert_eq!(Height::new(42), Height::new(42));
1124 }
1125
1126 #[test]
1127 fn test_height_encode_decode() {
1128 let cases = vec![0u64, 1, 127, 128, 255, 256, u64::MAX];
1129 for value in cases {
1130 let height = Height::new(value);
1131 let encoded = height.encode();
1132 assert_eq!(encoded.len(), height.encode_size());
1133 let decoded = Height::decode(encoded).unwrap();
1134 assert_eq!(height, decoded);
1135 }
1136 }
1137
1138 #[test]
1139 fn test_height_delta_from() {
1140 assert_eq!(
1141 Height::new(10).delta_from(Height::new(3)),
1142 Some(HeightDelta::new(7))
1143 );
1144 assert_eq!(
1145 Height::new(5).delta_from(Height::new(5)),
1146 Some(HeightDelta::zero())
1147 );
1148 assert_eq!(Height::new(3).delta_from(Height::new(10)), None);
1149 assert_eq!(Height::zero().delta_from(Height::new(1)), None);
1150 }
1151
1152 #[test]
1153 fn height_range_iterates() {
1154 let collected: Vec<_> = Height::range(Height::new(3), Height::new(6))
1155 .map(Height::get)
1156 .collect();
1157 assert_eq!(collected, vec![3, 4, 5]);
1158 }
1159
1160 #[test]
1161 fn height_range_empty() {
1162 let collected: Vec<_> = Height::range(Height::new(5), Height::new(5)).collect();
1163 assert_eq!(collected, vec![]);
1164
1165 let collected: Vec<_> = Height::range(Height::new(10), Height::new(5)).collect();
1166 assert_eq!(collected, vec![]);
1167 }
1168
1169 #[test]
1170 fn height_range_single() {
1171 let collected: Vec<_> = Height::range(Height::new(5), Height::new(6))
1172 .map(Height::get)
1173 .collect();
1174 assert_eq!(collected, vec![5]);
1175 }
1176
1177 #[test]
1178 fn height_range_size_hint() {
1179 let range = Height::range(Height::new(3), Height::new(10));
1180 assert_eq!(range.size_hint(), (7, Some(7)));
1181 assert_eq!(range.len(), 7);
1182
1183 let empty = Height::range(Height::new(5), Height::new(5));
1184 assert_eq!(empty.size_hint(), (0, Some(0)));
1185 assert_eq!(empty.len(), 0);
1186 }
1187
1188 #[test]
1189 fn height_range_rev() {
1190 let collected: Vec<_> = Height::range(Height::new(3), Height::new(7))
1191 .rev()
1192 .map(Height::get)
1193 .collect();
1194 assert_eq!(collected, vec![6, 5, 4, 3]);
1195 }
1196
1197 #[test]
1198 fn height_range_double_ended() {
1199 let mut range = Height::range(Height::new(5), Height::new(10));
1200 assert_eq!(range.next(), Some(Height::new(5)));
1201 assert_eq!(range.next_back(), Some(Height::new(9)));
1202 assert_eq!(range.next(), Some(Height::new(6)));
1203 assert_eq!(range.next_back(), Some(Height::new(8)));
1204 assert_eq!(range.len(), 1);
1205 assert_eq!(range.next(), Some(Height::new(7)));
1206 assert_eq!(range.next(), None);
1207 assert_eq!(range.next_back(), None);
1208 }
1209
1210 #[test]
1211 fn test_view_constructors() {
1212 assert_eq!(View::zero().get(), 0);
1213 assert_eq!(View::new(42).get(), 42);
1214 assert_eq!(View::new(100).get(), 100);
1215 assert_eq!(View::default().get(), 0);
1216 }
1217
1218 #[test]
1219 fn test_view_is_zero() {
1220 assert!(View::zero().is_zero());
1221 assert!(View::new(0).is_zero());
1222 assert!(!View::new(1).is_zero());
1223 assert!(!View::new(100).is_zero());
1224 }
1225
1226 #[test]
1227 fn test_view_next() {
1228 assert_eq!(View::zero().next().get(), 1);
1229 assert_eq!(View::new(5).next().get(), 6);
1230 assert_eq!(View::new(999).next().get(), 1000);
1231 }
1232
1233 #[test]
1234 #[should_panic(expected = "view overflow")]
1235 fn test_view_next_overflow() {
1236 View::new(u64::MAX).next();
1237 }
1238
1239 #[test]
1240 fn test_view_previous() {
1241 assert_eq!(View::zero().previous(), None);
1242 assert_eq!(View::new(1).previous(), Some(View::zero()));
1243 assert_eq!(View::new(5).previous(), Some(View::new(4)));
1244 assert_eq!(View::new(1000).previous(), Some(View::new(999)));
1245 }
1246
1247 #[test]
1248 fn test_view_saturating_add() {
1249 let delta5 = ViewDelta::new(5);
1250 let delta100 = ViewDelta::new(100);
1251 assert_eq!(View::zero().saturating_add(delta5).get(), 5);
1252 assert_eq!(View::new(10).saturating_add(delta100).get(), 110);
1253 assert_eq!(
1254 View::new(u64::MAX).saturating_add(ViewDelta::new(1)).get(),
1255 u64::MAX
1256 );
1257 }
1258
1259 #[test]
1260 fn test_view_saturating_sub() {
1261 let delta5 = ViewDelta::new(5);
1262 let delta100 = ViewDelta::new(100);
1263 assert_eq!(View::new(10).saturating_sub(delta5).get(), 5);
1264 assert_eq!(View::new(5).saturating_sub(delta5).get(), 0);
1265 assert_eq!(View::new(5).saturating_sub(delta100).get(), 0);
1266 assert_eq!(View::zero().saturating_sub(delta100).get(), 0);
1267 }
1268
1269 #[test]
1270 fn test_view_display() {
1271 assert_eq!(format!("{}", View::zero()), "0");
1272 assert_eq!(format!("{}", View::new(42)), "42");
1273 assert_eq!(format!("{}", View::new(1000)), "1000");
1274 }
1275
1276 #[test]
1277 fn test_view_ordering() {
1278 assert!(View::zero() < View::new(1));
1279 assert!(View::new(5) < View::new(10));
1280 assert!(View::new(10) > View::new(5));
1281 assert_eq!(View::new(42), View::new(42));
1282 }
1283
1284 #[test]
1285 fn test_view_encode_decode() {
1286 let cases = vec![0u64, 1, 127, 128, 255, 256, u64::MAX];
1287 for value in cases {
1288 let view = View::new(value);
1289 let encoded = view.encode();
1290 assert_eq!(encoded.len(), view.encode_size());
1291 let decoded = View::decode(encoded).unwrap();
1292 assert_eq!(view, decoded);
1293 }
1294 }
1295
1296 #[test]
1297 fn test_view_delta_constructors() {
1298 assert_eq!(ViewDelta::zero().get(), 0);
1299 assert_eq!(ViewDelta::new(42).get(), 42);
1300 assert_eq!(ViewDelta::new(100).get(), 100);
1301 assert_eq!(ViewDelta::default().get(), 0);
1302 }
1303
1304 #[test]
1305 fn test_view_delta_is_zero() {
1306 assert!(ViewDelta::zero().is_zero());
1307 assert!(ViewDelta::new(0).is_zero());
1308 assert!(!ViewDelta::new(1).is_zero());
1309 assert!(!ViewDelta::new(100).is_zero());
1310 }
1311
1312 #[test]
1313 fn test_view_delta_display() {
1314 assert_eq!(format!("{}", ViewDelta::zero()), "0");
1315 assert_eq!(format!("{}", ViewDelta::new(42)), "42");
1316 assert_eq!(format!("{}", ViewDelta::new(1000)), "1000");
1317 }
1318
1319 #[test]
1320 fn test_view_delta_ordering() {
1321 assert!(ViewDelta::zero() < ViewDelta::new(1));
1322 assert!(ViewDelta::new(5) < ViewDelta::new(10));
1323 assert!(ViewDelta::new(10) > ViewDelta::new(5));
1324 assert_eq!(ViewDelta::new(42), ViewDelta::new(42));
1325 }
1326
1327 #[test]
1328 fn test_round_cmp() {
1329 assert!(Round::new(Epoch::new(1), View::new(2)) < Round::new(Epoch::new(1), View::new(3)));
1330 assert!(Round::new(Epoch::new(1), View::new(2)) < Round::new(Epoch::new(2), View::new(1)));
1331 }
1332
1333 #[test]
1334 fn test_round_encode_decode_roundtrip() {
1335 let r: Round = (Epoch::new(42), View::new(1_000_000)).into();
1336 let encoded = r.encode();
1337 assert_eq!(encoded.len(), r.encode_size());
1338 let decoded = Round::decode(encoded).unwrap();
1339 assert_eq!(r, decoded);
1340 }
1341
1342 #[test]
1343 fn test_round_conversions() {
1344 let r: Round = (Epoch::new(5), View::new(6)).into();
1345 assert_eq!(r.epoch(), Epoch::new(5));
1346 assert_eq!(r.view(), View::new(6));
1347 let tuple: (Epoch, View) = r.into();
1348 assert_eq!(tuple, (Epoch::new(5), View::new(6)));
1349 }
1350
1351 #[test]
1352 fn test_round_new() {
1353 let r = Round::new(Epoch::new(10), View::new(20));
1354 assert_eq!(r.epoch(), Epoch::new(10));
1355 assert_eq!(r.view(), View::new(20));
1356
1357 let r2 = Round::new(Epoch::new(5), View::new(15));
1358 assert_eq!(r2.epoch(), Epoch::new(5));
1359 assert_eq!(r2.view(), View::new(15));
1360 }
1361
1362 #[test]
1363 fn test_round_display() {
1364 let r = Round::new(Epoch::new(5), View::new(100));
1365 assert_eq!(format!("{r}"), "(5, 100)");
1366 }
1367
1368 #[test]
1369 fn view_range_iterates() {
1370 let collected: Vec<_> = View::range(View::new(3), View::new(6))
1371 .map(View::get)
1372 .collect();
1373 assert_eq!(collected, vec![3, 4, 5]);
1374 }
1375
1376 #[test]
1377 fn view_range_empty() {
1378 let collected: Vec<_> = View::range(View::new(5), View::new(5)).collect();
1379 assert_eq!(collected, vec![]);
1380
1381 let collected: Vec<_> = View::range(View::new(10), View::new(5)).collect();
1382 assert_eq!(collected, vec![]);
1383 }
1384
1385 #[test]
1386 fn view_range_single() {
1387 let collected: Vec<_> = View::range(View::new(5), View::new(6))
1388 .map(View::get)
1389 .collect();
1390 assert_eq!(collected, vec![5]);
1391 }
1392
1393 #[test]
1394 fn view_range_size_hint() {
1395 let range = View::range(View::new(3), View::new(10));
1396 assert_eq!(range.size_hint(), (7, Some(7)));
1397 assert_eq!(range.len(), 7);
1398
1399 let empty = View::range(View::new(5), View::new(5));
1400 assert_eq!(empty.size_hint(), (0, Some(0)));
1401 assert_eq!(empty.len(), 0);
1402 }
1403
1404 #[test]
1405 fn view_range_collect() {
1406 let views: Vec<View> = View::range(View::new(0), View::new(3)).collect();
1407 assert_eq!(views, vec![View::zero(), View::new(1), View::new(2)]);
1408 }
1409
1410 #[test]
1411 fn view_range_iterator_next() {
1412 let mut range = View::range(View::new(5), View::new(8));
1413 assert_eq!(range.next(), Some(View::new(5)));
1414 assert_eq!(range.next(), Some(View::new(6)));
1415 assert_eq!(range.next(), Some(View::new(7)));
1416 assert_eq!(range.next(), None);
1417 assert_eq!(range.next(), None); }
1419
1420 #[test]
1421 fn view_range_exact_size_iterator() {
1422 let range = View::range(View::new(10), View::new(15));
1423 assert_eq!(range.len(), 5);
1424 assert_eq!(range.size_hint(), (5, Some(5)));
1425
1426 let mut range = View::range(View::new(10), View::new(15));
1427 assert_eq!(range.len(), 5);
1428 range.next();
1429 assert_eq!(range.len(), 4);
1430 range.next();
1431 assert_eq!(range.len(), 3);
1432 }
1433
1434 #[test]
1435 fn view_range_rev() {
1436 let collected: Vec<_> = View::range(View::new(3), View::new(7))
1438 .rev()
1439 .map(View::get)
1440 .collect();
1441 assert_eq!(collected, vec![6, 5, 4, 3]);
1442 }
1443
1444 #[test]
1445 fn view_range_double_ended() {
1446 let mut range = View::range(View::new(5), View::new(10));
1448 assert_eq!(range.next(), Some(View::new(5)));
1449 assert_eq!(range.next_back(), Some(View::new(9)));
1450 assert_eq!(range.next(), Some(View::new(6)));
1451 assert_eq!(range.next_back(), Some(View::new(8)));
1452 assert_eq!(range.len(), 1);
1453 assert_eq!(range.next(), Some(View::new(7)));
1454 assert_eq!(range.next(), None);
1455 assert_eq!(range.next_back(), None);
1456 }
1457
1458 #[test]
1459 fn test_fixed_epoch_strategy() {
1460 let epocher = FixedEpocher::new(NZU64!(100));
1461
1462 let bounds = epocher.containing(Height::zero()).unwrap();
1464 assert_eq!(bounds.epoch(), Epoch::new(0));
1465 assert_eq!(bounds.first(), Height::zero());
1466 assert_eq!(bounds.last(), Height::new(99));
1467 assert_eq!(bounds.length(), HeightDelta::new(100));
1468
1469 let bounds = epocher.containing(Height::new(99)).unwrap();
1470 assert_eq!(bounds.epoch(), Epoch::new(0));
1471
1472 let bounds = epocher.containing(Height::new(100)).unwrap();
1473 assert_eq!(bounds.epoch(), Epoch::new(1));
1474 assert_eq!(bounds.first(), Height::new(100));
1475 assert_eq!(bounds.last(), Height::new(199));
1476
1477 assert_eq!(epocher.first(Epoch::new(0)), Some(Height::zero()));
1479 assert_eq!(epocher.last(Epoch::new(0)), Some(Height::new(99)));
1480 assert_eq!(epocher.first(Epoch::new(1)), Some(Height::new(100)));
1481 assert_eq!(epocher.last(Epoch::new(1)), Some(Height::new(199)));
1482 assert_eq!(epocher.first(Epoch::new(5)), Some(Height::new(500)));
1483 assert_eq!(epocher.last(Epoch::new(5)), Some(Height::new(599)));
1484 }
1485
1486 #[test]
1487 fn test_epoch_bounds_relative() {
1488 let epocher = FixedEpocher::new(NZU64!(100));
1489
1490 assert_eq!(
1492 epocher.containing(Height::zero()).unwrap().relative(),
1493 Height::zero()
1494 );
1495 assert_eq!(
1496 epocher.containing(Height::new(50)).unwrap().relative(),
1497 Height::new(50)
1498 );
1499 assert_eq!(
1500 epocher.containing(Height::new(99)).unwrap().relative(),
1501 Height::new(99)
1502 );
1503
1504 assert_eq!(
1506 epocher.containing(Height::new(100)).unwrap().relative(),
1507 Height::zero()
1508 );
1509 assert_eq!(
1510 epocher.containing(Height::new(150)).unwrap().relative(),
1511 Height::new(50)
1512 );
1513 assert_eq!(
1514 epocher.containing(Height::new(199)).unwrap().relative(),
1515 Height::new(99)
1516 );
1517
1518 assert_eq!(
1520 epocher.containing(Height::new(500)).unwrap().relative(),
1521 Height::zero()
1522 );
1523 assert_eq!(
1524 epocher.containing(Height::new(567)).unwrap().relative(),
1525 Height::new(67)
1526 );
1527 assert_eq!(
1528 epocher.containing(Height::new(599)).unwrap().relative(),
1529 Height::new(99)
1530 );
1531 }
1532
1533 #[test]
1534 fn test_epoch_bounds_phase() {
1535 let epocher = FixedEpocher::new(NZU64!(30));
1537
1538 assert_eq!(
1540 epocher.containing(Height::zero()).unwrap().phase(),
1541 EpochPhase::Early
1542 );
1543 assert_eq!(
1544 epocher.containing(Height::new(14)).unwrap().phase(),
1545 EpochPhase::Early
1546 );
1547
1548 assert_eq!(
1550 epocher.containing(Height::new(15)).unwrap().phase(),
1551 EpochPhase::Midpoint
1552 );
1553
1554 assert_eq!(
1556 epocher.containing(Height::new(16)).unwrap().phase(),
1557 EpochPhase::Late
1558 );
1559 assert_eq!(
1560 epocher.containing(Height::new(29)).unwrap().phase(),
1561 EpochPhase::Late
1562 );
1563
1564 assert_eq!(
1566 epocher.containing(Height::new(30)).unwrap().phase(),
1567 EpochPhase::Early
1568 );
1569 assert_eq!(
1570 epocher.containing(Height::new(44)).unwrap().phase(),
1571 EpochPhase::Early
1572 );
1573 assert_eq!(
1574 epocher.containing(Height::new(45)).unwrap().phase(),
1575 EpochPhase::Midpoint
1576 );
1577 assert_eq!(
1578 epocher.containing(Height::new(46)).unwrap().phase(),
1579 EpochPhase::Late
1580 );
1581
1582 let epocher = FixedEpocher::new(NZU64!(10));
1584 assert_eq!(
1585 epocher.containing(Height::zero()).unwrap().phase(),
1586 EpochPhase::Early
1587 );
1588 assert_eq!(
1589 epocher.containing(Height::new(4)).unwrap().phase(),
1590 EpochPhase::Early
1591 );
1592 assert_eq!(
1593 epocher.containing(Height::new(5)).unwrap().phase(),
1594 EpochPhase::Midpoint
1595 );
1596 assert_eq!(
1597 epocher.containing(Height::new(6)).unwrap().phase(),
1598 EpochPhase::Late
1599 );
1600 assert_eq!(
1601 epocher.containing(Height::new(9)).unwrap().phase(),
1602 EpochPhase::Late
1603 );
1604
1605 let epocher = FixedEpocher::new(NZU64!(11));
1607 assert_eq!(
1608 epocher.containing(Height::zero()).unwrap().phase(),
1609 EpochPhase::Early
1610 );
1611 assert_eq!(
1612 epocher.containing(Height::new(4)).unwrap().phase(),
1613 EpochPhase::Early
1614 );
1615 assert_eq!(
1616 epocher.containing(Height::new(5)).unwrap().phase(),
1617 EpochPhase::Midpoint
1618 );
1619 assert_eq!(
1620 epocher.containing(Height::new(6)).unwrap().phase(),
1621 EpochPhase::Late
1622 );
1623 assert_eq!(
1624 epocher.containing(Height::new(10)).unwrap().phase(),
1625 EpochPhase::Late
1626 );
1627 }
1628
1629 #[test]
1630 fn test_fixed_epocher_overflow() {
1631 let epocher = FixedEpocher::new(NZU64!(100));
1633
1634 let last_valid_first = Height::new(18446744073709551500u64);
1643 let last_valid_last = Height::new(18446744073709551599u64);
1644
1645 let result = epocher.containing(last_valid_first);
1646 assert!(result.is_some());
1647 let bounds = result.unwrap();
1648 assert_eq!(bounds.first(), last_valid_first);
1649 assert_eq!(bounds.last(), last_valid_last);
1650
1651 let result = epocher.containing(last_valid_last);
1652 assert!(result.is_some());
1653 assert_eq!(result.unwrap().last(), last_valid_last);
1654
1655 let overflow_height = last_valid_last.next();
1657 assert!(epocher.containing(overflow_height).is_none());
1658
1659 assert!(epocher.containing(Height::new(u64::MAX)).is_none());
1661
1662 let epocher = FixedEpocher::new(NZU64!(2));
1664
1665 let result = epocher.containing(Height::new(u64::MAX - 1));
1667 assert!(result.is_some());
1668 assert_eq!(result.unwrap().last(), Height::new(u64::MAX));
1669
1670 let result = epocher.containing(Height::new(u64::MAX));
1673 assert!(result.is_some());
1674 assert_eq!(result.unwrap().last(), Height::new(u64::MAX));
1675
1676 let epocher = FixedEpocher::new(NZU64!(1));
1678 let result = epocher.containing(Height::new(u64::MAX));
1679 assert!(result.is_some());
1680 assert_eq!(result.unwrap().last(), Height::new(u64::MAX));
1681
1682 let epocher = FixedEpocher::new(NZU64!(u64::MAX));
1684 assert!(epocher.containing(Height::new(u64::MAX)).is_none());
1685
1686 let epocher = FixedEpocher::new(NZU64!(100));
1688 let last_valid_epoch = Epoch::new(184467440737095515);
1689 let first_invalid_epoch = Epoch::new(184467440737095516);
1690
1691 assert!(epocher.first(last_valid_epoch).is_some());
1693 assert!(epocher.last(last_valid_epoch).is_some());
1694 let first = epocher.first(last_valid_epoch).unwrap();
1695 assert!(epocher.containing(first).is_some());
1696 assert_eq!(
1697 epocher.containing(first).unwrap().last(),
1698 epocher.last(last_valid_epoch).unwrap()
1699 );
1700
1701 assert!(epocher.first(first_invalid_epoch).is_none());
1703 assert!(epocher.last(first_invalid_epoch).is_none());
1704 assert!(epocher.containing(last_valid_last.next()).is_none());
1705 }
1706
1707 #[test]
1708 fn test_coding_commitment_fallible_digest() {
1709 #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1710 struct Digest([u8; Self::SIZE]);
1711
1712 impl Random for Digest {
1713 fn random(mut rng: impl rand_core::CryptoRng) -> Self {
1714 let mut buf = [0u8; Self::SIZE];
1715 rng.fill_bytes(&mut buf);
1716 Self(buf)
1717 }
1718 }
1719
1720 impl commonware_cryptography::Digest for Digest {
1721 const EMPTY: Self = Self([0u8; Self::SIZE]);
1722 }
1723
1724 impl Write for Digest {
1725 fn write(&self, buf: &mut impl BufMut) {
1726 buf.put_slice(&self.0);
1727 }
1728 }
1729
1730 impl FixedSize for Digest {
1731 const SIZE: usize = 32;
1732 }
1733
1734 impl Read for Digest {
1735 type Cfg = ();
1736
1737 fn read_cfg(
1738 _: &mut impl bytes::Buf,
1739 _: &Self::Cfg,
1740 ) -> Result<Self, commonware_codec::Error> {
1741 Err(commonware_codec::Error::Invalid(
1742 "Digest",
1743 "read not implemented",
1744 ))
1745 }
1746 }
1747
1748 impl AsRef<[u8]> for Digest {
1749 fn as_ref(&self) -> &[u8] {
1750 &self.0
1751 }
1752 }
1753
1754 impl Deref for Digest {
1755 type Target = [u8];
1756
1757 fn deref(&self) -> &Self::Target {
1758 &self.0
1759 }
1760 }
1761
1762 impl core::fmt::Display for Digest {
1763 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1764 write!(f, "{}", commonware_formatting::Hex(self.as_ref()))
1765 }
1766 }
1767
1768 impl core::fmt::Debug for Digest {
1769 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1770 write!(f, "Digest({})", commonware_formatting::Hex(self.as_ref()))
1771 }
1772 }
1773
1774 impl Span for Digest {}
1775 impl Array for Digest {}
1776
1777 let digest = Digest::random(test_rng());
1778 let commitment = Commitment::from((
1779 digest,
1780 digest,
1781 digest,
1782 CodingConfig {
1783 minimum_shards: NZU16!(1),
1784 extra_shards: NZU16!(1),
1785 },
1786 ));
1787
1788 let encoded = commitment.encode();
1790 let decoded = Commitment::decode(encoded).unwrap();
1791
1792 let result = std::panic::catch_unwind(|| decoded.block::<Digest>());
1794 assert!(result.is_err());
1795 let result = std::panic::catch_unwind(|| decoded.root::<Digest>());
1796 assert!(result.is_err());
1797 let result = std::panic::catch_unwind(|| decoded.context::<Digest>());
1798 assert!(result.is_err());
1799 let result = std::panic::catch_unwind(|| decoded.config());
1800 assert!(result.is_ok());
1801 }
1802
1803 #[cfg(feature = "arbitrary")]
1804 mod conformance {
1805 use super::{coding::Commitment, *};
1806 use commonware_codec::conformance::CodecConformance;
1807
1808 commonware_conformance::conformance_tests! {
1809 CodecConformance<Epoch>,
1810 CodecConformance<Height>,
1811 CodecConformance<View>,
1812 CodecConformance<Round>,
1813 CodecConformance<Commitment>,
1814 }
1815 }
1816}