casper_types/chainspec/
activation_point.rs

1use std::fmt::{self, Display, Formatter};
2
3#[cfg(feature = "datasize")]
4use datasize::DataSize;
5#[cfg(any(feature = "testing", test))]
6use rand::Rng;
7#[cfg(feature = "json-schema")]
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10
11#[cfg(any(feature = "testing", test))]
12use crate::testing::TestRng;
13use crate::{
14    bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
15    EraId, TimeDiff, Timestamp,
16};
17
18const ERA_ID_TAG: u8 = 0;
19const GENESIS_TAG: u8 = 1;
20
21/// The first era to which the associated protocol version applies.
22#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
23#[cfg_attr(feature = "datasize", derive(DataSize))]
24#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
25#[serde(untagged)]
26pub enum ActivationPoint {
27    /// Era id.
28    EraId(EraId),
29    /// Genesis timestamp.
30    Genesis(Timestamp),
31}
32
33impl ActivationPoint {
34    /// Returns whether we should upgrade the node due to the next era being the upgrade activation
35    /// point.
36    pub fn should_upgrade(&self, era_being_deactivated: &EraId) -> bool {
37        match self {
38            ActivationPoint::EraId(era_id) => era_being_deactivated.successor() >= *era_id,
39            ActivationPoint::Genesis(_) => false,
40        }
41    }
42
43    /// Returns the Era ID if `self` is of `EraId` variant, or else 0 if `Genesis`.
44    pub fn era_id(&self) -> EraId {
45        match self {
46            ActivationPoint::EraId(era_id) => *era_id,
47            ActivationPoint::Genesis(_) => EraId::from(0),
48        }
49    }
50
51    /// Returns the timestamp if `self` is of `Genesis` variant, or else `None`.
52    pub fn genesis_timestamp(&self) -> Option<Timestamp> {
53        match self {
54            ActivationPoint::EraId(_) => None,
55            ActivationPoint::Genesis(timestamp) => Some(*timestamp),
56        }
57    }
58
59    /// Returns a random `ActivationPoint`.
60    #[cfg(any(feature = "testing", test))]
61    pub fn random(rng: &mut TestRng) -> Self {
62        if rng.gen() {
63            ActivationPoint::EraId(EraId::random(rng))
64        } else {
65            ActivationPoint::Genesis(Timestamp::random(rng))
66        }
67    }
68}
69
70impl Default for ActivationPoint {
71    fn default() -> Self {
72        ActivationPoint::Genesis(Timestamp::now().saturating_add(TimeDiff::from_seconds(15)))
73    }
74}
75
76impl Display for ActivationPoint {
77    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
78        match self {
79            ActivationPoint::EraId(era_id) => write!(formatter, "activation point {}", era_id),
80            ActivationPoint::Genesis(timestamp) => {
81                write!(formatter, "activation point {}", timestamp)
82            }
83        }
84    }
85}
86
87impl ToBytes for ActivationPoint {
88    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
89        match self {
90            ActivationPoint::EraId(era_id) => {
91                let mut buffer = vec![ERA_ID_TAG];
92                buffer.extend(era_id.to_bytes()?);
93                Ok(buffer)
94            }
95            ActivationPoint::Genesis(timestamp) => {
96                let mut buffer = vec![GENESIS_TAG];
97                buffer.extend(timestamp.to_bytes()?);
98                Ok(buffer)
99            }
100        }
101    }
102
103    fn serialized_length(&self) -> usize {
104        U8_SERIALIZED_LENGTH
105            + match self {
106                ActivationPoint::EraId(era_id) => era_id.serialized_length(),
107                ActivationPoint::Genesis(timestamp) => timestamp.serialized_length(),
108            }
109    }
110}
111
112impl FromBytes for ActivationPoint {
113    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
114        let (tag, remainder) = u8::from_bytes(bytes)?;
115        match tag {
116            ERA_ID_TAG => {
117                let (era_id, remainder) = EraId::from_bytes(remainder)?;
118                Ok((ActivationPoint::EraId(era_id), remainder))
119            }
120            GENESIS_TAG => {
121                let (timestamp, remainder) = Timestamp::from_bytes(remainder)?;
122                Ok((ActivationPoint::Genesis(timestamp), remainder))
123            }
124            _ => Err(bytesrepr::Error::Formatting),
125        }
126    }
127}