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