radix_common/types/consensus.rs
1use sbor::Sbor;
2
3/// An index of a specific validator within the current validator set.
4/// To be exact: a `ValidatorIndex` equal to `k` references the `k-th` element returned by the
5/// iterator of the `IndexMap<ComponentAddress, Validator>` in this epoch's active validator set
6/// (which is expected to be sorted by stake, descending).
7/// This uniquely identifies the validator, while being shorter than `ComponentAddress` (we do care
8/// about the constant factor of the space taken by `LeaderProposalHistory` under prolonged liveness
9/// break scenarios).
10pub type ValidatorIndex = u8;
11
12/// A type-safe consensus epoch number.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Sbor)]
14#[sbor(transparent)]
15pub struct Epoch(u64);
16
17impl Epoch {
18 /// Creates a zero epoch (i.e. pre-genesis).
19 pub fn zero() -> Self {
20 Self::of(0)
21 }
22
23 /// Creates an epoch of the given number.
24 pub fn of(number: u64) -> Self {
25 Self(number)
26 }
27
28 /// Returns a raw epoch number.
29 pub fn number(&self) -> u64 {
30 self.0
31 }
32
33 /// Creates an epoch immediately following this one.
34 /// Returns `None` if this epoch's number is [`u64::MAX`] (such situation would indicate a bug
35 /// or a deliberate harm meant by byzantine actors, since regular epoch progression should not
36 /// reach such numbers within next thousands of years).
37 pub fn next(&self) -> Option<Self> {
38 self.0.checked_add(1).map(Self)
39 }
40
41 /// Creates an epoch following this one after the given number of epochs.
42 /// Returns `None` if the resulting number is greater than [`u64::MAX`] (such situation would
43 /// indicate a bug or a deliberate harm meant by byzantine actors, since regular epoch delays
44 /// configured by a network should not span thousands of years).
45 pub fn after(&self, epoch_count: u64) -> Option<Self> {
46 self.0.checked_add(epoch_count).map(Self)
47 }
48
49 /// Creates an epoch immediately preceding this one.
50 /// Returns `None` if this epoch's number is 0 (such situation would indicate a bug or a
51 /// deliberate harm, since a legitimate genesis should not reference previous epochs).
52 pub fn previous(&self) -> Option<Self> {
53 self.0.checked_sub(1).map(Self)
54 }
55}
56
57/// A type-safe consensus round number *within a single epoch*.
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Sbor)]
59#[sbor(transparent)]
60pub struct Round(u64);
61
62impl Round {
63 /// Creates a zero round (i.e. a state right after progressing to a next epoch).
64 pub fn zero() -> Self {
65 Self::of(0)
66 }
67
68 /// Creates a round of the given number.
69 pub fn of(number: u64) -> Self {
70 Self(number)
71 }
72
73 /// Returns a raw round number.
74 pub fn number(&self) -> u64 {
75 self.0
76 }
77
78 /// Returns a number of rounds between `from` and `to`, or `None` if there was no progress
79 /// (i.e. their difference was not positive).
80 pub fn calculate_progress(from: Round, to: Round) -> Option<u64> {
81 let difference = (to.0 as i128) - (from.0 as i128);
82 if difference <= 0 {
83 None
84 } else {
85 Some(difference as u64) // if a difference of two u64 is positive, then it fits in u64
86 }
87 }
88}