casper_types/account/
action_thresholds.rs

1//! This module contains types and functions for managing action thresholds.
2
3use alloc::vec::Vec;
4
5#[cfg(feature = "datasize")]
6use datasize::DataSize;
7#[cfg(feature = "json-schema")]
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10
11use crate::{
12    account::{ActionType, SetThresholdFailure, Weight},
13    addressable_entity::WEIGHT_SERIALIZED_LENGTH,
14    bytesrepr::{self, Error, FromBytes, ToBytes},
15};
16
17/// Thresholds that have to be met when executing an action of a certain type.
18#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
19#[cfg_attr(feature = "datasize", derive(DataSize))]
20#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
21#[cfg_attr(feature = "json-schema", schemars(rename = "AccountActionThresholds"))]
22pub struct ActionThresholds {
23    /// Threshold for deploy execution.
24    pub deployment: Weight,
25    /// Threshold for managing action threshold.
26    pub key_management: Weight,
27}
28
29impl ActionThresholds {
30    /// Creates new ActionThresholds object with provided weights
31    ///
32    /// Requires deployment threshold to be lower than or equal to
33    /// key management threshold.
34    pub fn new(
35        deployment: Weight,
36        key_management: Weight,
37    ) -> Result<ActionThresholds, SetThresholdFailure> {
38        if deployment > key_management {
39            return Err(SetThresholdFailure::DeploymentThreshold);
40        }
41        Ok(ActionThresholds {
42            deployment,
43            key_management,
44        })
45    }
46    /// Sets new threshold for [ActionType::Deployment].
47    /// Should return an error if setting new threshold for `action_type` breaks
48    /// one of the invariants. Currently, invariant is that
49    /// `ActionType::Deployment` threshold shouldn't be higher than any
50    /// other, which should be checked both when increasing `Deployment`
51    /// threshold and decreasing the other.
52    pub fn set_deployment_threshold(
53        &mut self,
54        new_threshold: Weight,
55    ) -> Result<(), SetThresholdFailure> {
56        if new_threshold > self.key_management {
57            Err(SetThresholdFailure::DeploymentThreshold)
58        } else {
59            self.deployment = new_threshold;
60            Ok(())
61        }
62    }
63
64    /// Sets new threshold for [ActionType::KeyManagement].
65    pub fn set_key_management_threshold(
66        &mut self,
67        new_threshold: Weight,
68    ) -> Result<(), SetThresholdFailure> {
69        if self.deployment > new_threshold {
70            Err(SetThresholdFailure::KeyManagementThreshold)
71        } else {
72            self.key_management = new_threshold;
73            Ok(())
74        }
75    }
76
77    /// Returns the deployment action threshold.
78    pub fn deployment(&self) -> &Weight {
79        &self.deployment
80    }
81
82    /// Returns key management action threshold.
83    pub fn key_management(&self) -> &Weight {
84        &self.key_management
85    }
86
87    /// Unified function that takes an action type, and changes appropriate
88    /// threshold defined by the [ActionType] variants.
89    pub fn set_threshold(
90        &mut self,
91        action_type: ActionType,
92        new_threshold: Weight,
93    ) -> Result<(), SetThresholdFailure> {
94        match action_type {
95            ActionType::Deployment => self.set_deployment_threshold(new_threshold),
96            ActionType::KeyManagement => self.set_key_management_threshold(new_threshold),
97        }
98    }
99}
100
101impl Default for ActionThresholds {
102    fn default() -> Self {
103        ActionThresholds {
104            deployment: Weight::new(1),
105            key_management: Weight::new(1),
106        }
107    }
108}
109
110impl ToBytes for ActionThresholds {
111    fn to_bytes(&self) -> Result<Vec<u8>, Error> {
112        let mut result = bytesrepr::unchecked_allocate_buffer(self);
113        result.append(&mut self.deployment.to_bytes()?);
114        result.append(&mut self.key_management.to_bytes()?);
115        Ok(result)
116    }
117
118    fn serialized_length(&self) -> usize {
119        2 * WEIGHT_SERIALIZED_LENGTH
120    }
121
122    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
123        self.deployment().write_bytes(writer)?;
124        self.key_management().write_bytes(writer)?;
125        Ok(())
126    }
127}
128
129impl FromBytes for ActionThresholds {
130    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
131        let (deployment, rem) = Weight::from_bytes(bytes)?;
132        let (key_management, rem) = Weight::from_bytes(rem)?;
133        let ret = ActionThresholds {
134            deployment,
135            key_management,
136        };
137        Ok((ret, rem))
138    }
139}
140
141#[doc(hidden)]
142#[cfg(any(feature = "testing", feature = "gens", test))]
143pub mod gens {
144    use proptest::prelude::*;
145
146    use super::ActionThresholds;
147
148    pub fn account_action_thresholds_arb() -> impl Strategy<Value = ActionThresholds> {
149        Just(Default::default())
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156
157    #[test]
158    fn should_create_new_action_thresholds() {
159        let action_thresholds = ActionThresholds::new(Weight::new(1), Weight::new(42)).unwrap();
160        assert_eq!(*action_thresholds.deployment(), Weight::new(1));
161        assert_eq!(*action_thresholds.key_management(), Weight::new(42));
162    }
163
164    #[test]
165    fn should_not_create_action_thresholds_with_invalid_deployment_threshold() {
166        // deployment cant be greater than key management
167        assert!(ActionThresholds::new(Weight::new(5), Weight::new(1)).is_err());
168    }
169
170    #[test]
171    fn serialization_roundtrip() {
172        let action_thresholds = ActionThresholds::new(Weight::new(1), Weight::new(42)).unwrap();
173        bytesrepr::test_serialization_roundtrip(&action_thresholds);
174    }
175}