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}