casper_types/chainspec/
protocol_config.rs

1#[cfg(feature = "datasize")]
2use datasize::DataSize;
3#[cfg(any(feature = "testing", test))]
4use rand::Rng;
5use serde::{Deserialize, Serialize};
6use std::{collections::BTreeMap, str::FromStr};
7
8#[cfg(any(feature = "testing", test))]
9use crate::testing::TestRng;
10use crate::{
11    bytesrepr::{self, FromBytes, ToBytes},
12    Key, ProtocolVersion, StoredValue, Timestamp,
13};
14
15use crate::{ActivationPoint, GlobalStateUpdate};
16
17/// Configuration values associated with the protocol.
18#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
19#[cfg_attr(feature = "datasize", derive(DataSize))]
20pub struct ProtocolConfig {
21    /// Protocol version.
22    #[cfg_attr(feature = "datasize", data_size(skip))]
23    pub version: ProtocolVersion,
24    /// Whether we need to clear latest blocks back to the switch block just before the activation
25    /// point or not.
26    pub hard_reset: bool,
27    /// This protocol config applies starting at the era specified in the activation point.
28    pub activation_point: ActivationPoint,
29    /// Any arbitrary updates we might want to make to the global state at the start of the era
30    /// specified in the activation point.
31    pub global_state_update: Option<GlobalStateUpdate>,
32}
33
34impl ProtocolConfig {
35    /// The mapping of [`Key`]s to [`StoredValue`]s we will use to update global storage in the
36    /// event of an emergency update.
37    pub(crate) fn get_update_mapping(
38        &self,
39    ) -> Result<BTreeMap<Key, StoredValue>, bytesrepr::Error> {
40        let state_update = match &self.global_state_update {
41            Some(GlobalStateUpdate { entries, .. }) => entries,
42            None => return Ok(BTreeMap::default()),
43        };
44        let mut update_mapping = BTreeMap::new();
45        for (key, stored_value_bytes) in state_update {
46            let stored_value = bytesrepr::deserialize(stored_value_bytes.clone().into())?;
47            update_mapping.insert(*key, stored_value);
48        }
49        Ok(update_mapping)
50    }
51
52    /// Returns a random `ProtocolConfig`.
53    #[cfg(any(feature = "testing", test))]
54    pub fn random(rng: &mut TestRng) -> Self {
55        let protocol_version = ProtocolVersion::from_parts(
56            rng.gen_range(0..10),
57            rng.gen::<u8>() as u32,
58            rng.gen::<u8>() as u32,
59        );
60        let activation_point = ActivationPoint::random(rng);
61
62        ProtocolConfig {
63            version: protocol_version,
64            hard_reset: rng.gen(),
65            activation_point,
66            global_state_update: None,
67        }
68    }
69}
70
71impl ToBytes for ProtocolConfig {
72    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
73        let mut buffer = bytesrepr::allocate_buffer(self)?;
74        buffer.extend(self.version.to_string().to_bytes()?);
75        buffer.extend(self.hard_reset.to_bytes()?);
76        buffer.extend(self.activation_point.to_bytes()?);
77        buffer.extend(self.global_state_update.to_bytes()?);
78        Ok(buffer)
79    }
80
81    fn serialized_length(&self) -> usize {
82        self.version.to_string().serialized_length()
83            + self.hard_reset.serialized_length()
84            + self.activation_point.serialized_length()
85            + self.global_state_update.serialized_length()
86    }
87}
88
89impl FromBytes for ProtocolConfig {
90    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
91        let (protocol_version_string, remainder) = String::from_bytes(bytes)?;
92        let version = ProtocolVersion::from_str(&protocol_version_string)
93            .map_err(|_| bytesrepr::Error::Formatting)?;
94        let (hard_reset, remainder) = bool::from_bytes(remainder)?;
95        let (activation_point, remainder) = ActivationPoint::from_bytes(remainder)?;
96        let (global_state_update, remainder) = Option::<GlobalStateUpdate>::from_bytes(remainder)?;
97        let protocol_config = ProtocolConfig {
98            version,
99            hard_reset,
100            activation_point,
101            global_state_update,
102        };
103        Ok((protocol_config, remainder))
104    }
105}
106
107impl Default for ProtocolConfig {
108    fn default() -> Self {
109        ProtocolConfig {
110            activation_point: ActivationPoint::Genesis(Timestamp::now()),
111            global_state_update: None,
112            hard_reset: true,
113            version: ProtocolVersion::V2_0_0,
114        }
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121    use rand::SeedableRng;
122
123    #[test]
124    fn activation_point_bytesrepr_roundtrip() {
125        let mut rng = TestRng::from_entropy();
126        let activation_point = ActivationPoint::random(&mut rng);
127        bytesrepr::test_serialization_roundtrip(&activation_point);
128    }
129
130    #[test]
131    fn protocol_config_bytesrepr_roundtrip() {
132        let mut rng = TestRng::from_entropy();
133        let config = ProtocolConfig::random(&mut rng);
134        bytesrepr::test_serialization_roundtrip(&config);
135    }
136}