Skip to main content

lexe_common/api/
version.rs

1use std::{collections::BTreeSet, fmt};
2
3use lexe_enclave::enclave::{MachineId, Measurement};
4use lexe_std::fmt::DisplayIter;
5#[cfg(any(test, feature = "test-utils"))]
6use proptest_derive::Arbitrary;
7use serde::{Deserialize, Serialize};
8
9#[cfg(any(test, feature = "test-utils"))]
10use crate::test_utils::arbitrary;
11
12/// Upgradeable API struct for a measurement.
13#[derive(Debug, PartialEq, Serialize, Deserialize)]
14#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
15pub struct MeasurementStruct {
16    pub measurement: Measurement,
17}
18
19/// API-upgradeable struct for a [`BTreeSet<NodeEnclave>`].
20#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
21#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
22pub struct CurrentEnclaves {
23    /// All current node enclaves.
24    /// TODO(maurice): remove rename after v0.8.7 is gone.
25    #[serde(rename = "releases", alias = "enclaves")]
26    pub enclaves: BTreeSet<NodeEnclave>,
27}
28
29impl CurrentEnclaves {
30    /// Returns the latest (most recent) node enclave, if any.
31    pub fn latest(&self) -> Option<&NodeEnclave> {
32        self.enclaves.last()
33    }
34}
35
36/// The subset of node enclaves that a specific user needs to provision to.
37#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
38#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
39pub struct EnclavesToProvision {
40    pub enclaves: BTreeSet<NodeEnclave>,
41}
42
43impl fmt::Display for EnclavesToProvision {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        DisplayIter(self.enclaves.iter()).fmt(f)
46    }
47}
48
49/// The machine_id, semver version and measurement of a node enclave.
50///
51/// [`Ord`]ered by [`semver::Version`] precedence.
52#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
53#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
54pub struct NodeEnclave {
55    /// e.g. "0.1.0", "0.0.0-dev.1"
56    #[cfg_attr(
57        any(test, feature = "test-utils"),
58        proptest(strategy = "arbitrary::any_semver_version()")
59    )]
60    pub version: semver::Version,
61    pub measurement: Measurement,
62    pub machine_id: MachineId,
63}
64
65impl Ord for NodeEnclave {
66    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
67        self.version
68            .cmp_precedence(&other.version)
69            .then_with(|| self.machine_id.cmp(&other.machine_id))
70    }
71}
72
73impl PartialOrd for NodeEnclave {
74    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
75        Some(self.cmp(other))
76    }
77}
78
79impl fmt::Display for NodeEnclave {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        let version = &self.version;
82        let measurement = &self.measurement;
83        let machine_id = &self.machine_id;
84        write!(
85            f,
86            "(version=node-v{version}, measurement={measurement}, machine_id={machine_id})"
87        )
88    }
89}
90
91#[cfg(test)]
92mod test {
93    use super::*;
94    use crate::test_utils::roundtrip;
95
96    #[test]
97    fn measurement_struct_roundtrip() {
98        roundtrip::query_string_roundtrip_proptest::<MeasurementStruct>();
99    }
100
101    #[test]
102    fn node_enclave_roundtrip() {
103        roundtrip::json_value_roundtrip_proptest::<NodeEnclave>();
104    }
105}