casper_types/
validator_change.rs

1use crate::bytesrepr::{self, FromBytes, ToBytes};
2#[cfg(any(feature = "testing", test))]
3use crate::testing::TestRng;
4use alloc::vec::Vec;
5#[cfg(feature = "datasize")]
6use datasize::DataSize;
7#[cfg(feature = "json-schema")]
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10
11/// A change to a validator's status between two eras.
12#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd)]
13#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
14#[cfg_attr(feature = "datasize", derive(DataSize))]
15pub enum ValidatorChange {
16    /// The validator got newly added to the validator set.
17    Added,
18    /// The validator was removed from the validator set.
19    Removed,
20    /// The validator was banned from this era.
21    Banned,
22    /// The validator was excluded from proposing new blocks in this era.
23    CannotPropose,
24    /// We saw the validator misbehave in this era.
25    SeenAsFaulty,
26}
27
28impl ValidatorChange {
29    /// Returns a random `ValidatorChange`.
30    #[cfg(any(feature = "testing", test))]
31    pub fn random(rng: &mut TestRng) -> Self {
32        use rand::Rng;
33
34        match rng.gen_range(0..5) {
35            ADDED_TAG => ValidatorChange::Added,
36            REMOVED_TAG => ValidatorChange::Removed,
37            BANNED_TAG => ValidatorChange::Banned,
38            CANNOT_PROPOSE_TAG => ValidatorChange::CannotPropose,
39            SEEN_AS_FAULTY_TAG => ValidatorChange::SeenAsFaulty,
40            _ => unreachable!(),
41        }
42    }
43}
44
45const ADDED_TAG: u8 = 0;
46const REMOVED_TAG: u8 = 1;
47const BANNED_TAG: u8 = 2;
48const CANNOT_PROPOSE_TAG: u8 = 3;
49const SEEN_AS_FAULTY_TAG: u8 = 4;
50
51impl ToBytes for ValidatorChange {
52    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
53        let mut buffer = bytesrepr::allocate_buffer(self)?;
54        self.write_bytes(&mut buffer)?;
55        Ok(buffer)
56    }
57
58    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
59        match self {
60            ValidatorChange::Added => ADDED_TAG,
61            ValidatorChange::Removed => REMOVED_TAG,
62            ValidatorChange::Banned => BANNED_TAG,
63            ValidatorChange::CannotPropose => CANNOT_PROPOSE_TAG,
64            ValidatorChange::SeenAsFaulty => SEEN_AS_FAULTY_TAG,
65        }
66        .write_bytes(writer)
67    }
68
69    fn serialized_length(&self) -> usize {
70        bytesrepr::U8_SERIALIZED_LENGTH
71    }
72}
73
74impl FromBytes for ValidatorChange {
75    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
76        let (tag, remainder) = u8::from_bytes(bytes)?;
77        let id = match tag {
78            ADDED_TAG => ValidatorChange::Added,
79            REMOVED_TAG => ValidatorChange::Removed,
80            BANNED_TAG => ValidatorChange::Banned,
81            CANNOT_PROPOSE_TAG => ValidatorChange::CannotPropose,
82            SEEN_AS_FAULTY_TAG => ValidatorChange::SeenAsFaulty,
83            _ => return Err(bytesrepr::Error::NotRepresentable),
84        };
85        Ok((id, remainder))
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use crate::testing::TestRng;
93
94    #[test]
95    fn bytesrepr_roundtrip() {
96        let rng = &mut TestRng::new();
97
98        let val = ValidatorChange::random(rng);
99        bytesrepr::test_serialization_roundtrip(&val);
100    }
101}