casper_types/
protocol_version.rs

1use alloc::{format, string::String, vec::Vec};
2use core::{convert::TryFrom, fmt, str::FromStr};
3
4#[cfg(feature = "datasize")]
5use datasize::DataSize;
6#[cfg(feature = "json-schema")]
7use schemars::JsonSchema;
8use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
9
10use crate::{
11    bytesrepr::{Error, FromBytes, ToBytes},
12    ParseSemVerError, SemVer,
13};
14
15/// A newtype wrapping a [`SemVer`] which represents a Casper Platform protocol version.
16#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
17#[cfg_attr(feature = "datasize", derive(DataSize))]
18pub struct ProtocolVersion(SemVer);
19
20/// The result of [`ProtocolVersion::check_next_version`].
21#[derive(Debug, PartialEq, Eq)]
22pub enum VersionCheckResult {
23    /// Upgrade possible.
24    Valid {
25        /// Is this a major protocol version upgrade?
26        is_major_version: bool,
27    },
28    /// Upgrade is invalid.
29    Invalid,
30}
31
32impl VersionCheckResult {
33    /// Checks if given version result is invalid.
34    ///
35    /// Invalid means that a given version can not be followed.
36    pub fn is_invalid(&self) -> bool {
37        matches!(self, VersionCheckResult::Invalid)
38    }
39
40    /// Checks if given version is a major protocol version upgrade.
41    pub fn is_major_version(&self) -> bool {
42        match self {
43            VersionCheckResult::Valid { is_major_version } => *is_major_version,
44            VersionCheckResult::Invalid => false,
45        }
46    }
47}
48
49impl ProtocolVersion {
50    /// Version 1.0.0.
51    pub const V1_0_0: ProtocolVersion = ProtocolVersion(SemVer {
52        major: 1,
53        minor: 0,
54        patch: 0,
55    });
56
57    /// Version 2.0.0.
58    pub const V2_0_0: ProtocolVersion = ProtocolVersion(SemVer {
59        major: 2,
60        minor: 0,
61        patch: 0,
62    });
63
64    /// Constructs a new `ProtocolVersion` from `version`.
65    pub const fn new(version: SemVer) -> ProtocolVersion {
66        ProtocolVersion(version)
67    }
68
69    /// Constructs a new `ProtocolVersion` from the given semver parts.
70    pub const fn from_parts(major: u32, minor: u32, patch: u32) -> ProtocolVersion {
71        let sem_ver = SemVer::new(major, minor, patch);
72        Self::new(sem_ver)
73    }
74
75    /// Returns the inner [`SemVer`].
76    pub const fn value(&self) -> SemVer {
77        self.0
78    }
79
80    /// Returns the inner [`SemVer`] destructed into a tuple of (major, minor, patch).
81    pub const fn destructure(&self) -> (u32, u32, u32) {
82        (self.0.major, self.0.minor, self.0.patch)
83    }
84
85    /// Checks if next version can be followed.
86    pub fn check_next_version(&self, next: &ProtocolVersion) -> VersionCheckResult {
87        // Protocol major versions should increase monotonically by 1.
88        let major_bumped = self.0.major.saturating_add(1);
89        if next.0.major < self.0.major || next.0.major > major_bumped {
90            return VersionCheckResult::Invalid;
91        }
92
93        if next.0.major == major_bumped {
94            return VersionCheckResult::Valid {
95                is_major_version: true,
96            };
97        }
98
99        // Covers the equal major versions
100        debug_assert_eq!(next.0.major, self.0.major);
101
102        if next.0.minor < self.0.minor {
103            // Protocol minor versions within the same major version should not go backwards.
104            return VersionCheckResult::Invalid;
105        }
106
107        if next.0.minor > self.0.minor {
108            return VersionCheckResult::Valid {
109                is_major_version: false,
110            };
111        }
112
113        // Code belows covers equal minor versions
114        debug_assert_eq!(next.0.minor, self.0.minor);
115
116        // Protocol patch versions should increase monotonically but can be skipped.
117        if next.0.patch <= self.0.patch {
118            return VersionCheckResult::Invalid;
119        }
120
121        VersionCheckResult::Valid {
122            is_major_version: false,
123        }
124    }
125
126    /// Checks if given protocol version is compatible with current one.
127    ///
128    /// Two protocol versions with different major version are considered to be incompatible.
129    pub fn is_compatible_with(&self, version: &ProtocolVersion) -> bool {
130        self.0.major == version.0.major
131    }
132}
133
134impl ToBytes for ProtocolVersion {
135    fn to_bytes(&self) -> Result<Vec<u8>, Error> {
136        self.value().to_bytes()
137    }
138
139    fn serialized_length(&self) -> usize {
140        self.value().serialized_length()
141    }
142
143    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), Error> {
144        writer.extend(self.0.major.to_le_bytes());
145        writer.extend(self.0.minor.to_le_bytes());
146        writer.extend(self.0.patch.to_le_bytes());
147        Ok(())
148    }
149}
150
151impl FromBytes for ProtocolVersion {
152    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error> {
153        let (version, rem) = SemVer::from_bytes(bytes)?;
154        let protocol_version = ProtocolVersion::new(version);
155        Ok((protocol_version, rem))
156    }
157}
158
159impl FromStr for ProtocolVersion {
160    type Err = ParseSemVerError;
161
162    fn from_str(s: &str) -> Result<Self, ParseSemVerError> {
163        let version = SemVer::try_from(s)?;
164        Ok(ProtocolVersion::new(version))
165    }
166}
167
168impl Serialize for ProtocolVersion {
169    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
170        if serializer.is_human_readable() {
171            let str = format!("{}.{}.{}", self.0.major, self.0.minor, self.0.patch);
172            String::serialize(&str, serializer)
173        } else {
174            self.0.serialize(serializer)
175        }
176    }
177}
178
179impl<'de> Deserialize<'de> for ProtocolVersion {
180    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
181        let semver = if deserializer.is_human_readable() {
182            let value_as_string = String::deserialize(deserializer)?;
183            SemVer::try_from(value_as_string.as_str()).map_err(SerdeError::custom)?
184        } else {
185            SemVer::deserialize(deserializer)?
186        };
187        Ok(ProtocolVersion(semver))
188    }
189}
190
191#[cfg(feature = "json-schema")]
192impl JsonSchema for ProtocolVersion {
193    fn schema_name() -> String {
194        String::from("ProtocolVersion")
195    }
196
197    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
198        let schema = gen.subschema_for::<String>();
199        let mut schema_object = schema.into_object();
200        schema_object.metadata().description = Some("Casper Platform protocol version".to_string());
201        schema_object.into()
202    }
203}
204
205impl fmt::Display for ProtocolVersion {
206    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207        self.0.fmt(f)
208    }
209}
210
211#[cfg(test)]
212mod tests {
213    use super::*;
214    use crate::SemVer;
215
216    #[test]
217    fn should_follow_version_with_optional_code() {
218        let value = VersionCheckResult::Valid {
219            is_major_version: false,
220        };
221        assert!(!value.is_invalid());
222        assert!(!value.is_major_version());
223    }
224
225    #[test]
226    fn should_follow_version_with_required_code() {
227        let value = VersionCheckResult::Valid {
228            is_major_version: true,
229        };
230        assert!(!value.is_invalid());
231        assert!(value.is_major_version());
232    }
233
234    #[test]
235    fn should_not_follow_version_with_invalid_code() {
236        let value = VersionCheckResult::Invalid;
237        assert!(value.is_invalid());
238        assert!(!value.is_major_version());
239    }
240
241    #[test]
242    fn should_be_able_to_get_instance() {
243        let initial_value = SemVer::new(1, 0, 0);
244        let item = ProtocolVersion::new(initial_value);
245        assert_eq!(initial_value, item.value(), "should have equal value")
246    }
247
248    #[test]
249    fn should_be_able_to_compare_two_instances() {
250        let lhs = ProtocolVersion::new(SemVer::new(1, 0, 0));
251        let rhs = ProtocolVersion::new(SemVer::new(1, 0, 0));
252        assert_eq!(lhs, rhs, "should be equal");
253        let rhs = ProtocolVersion::new(SemVer::new(2, 0, 0));
254        assert_ne!(lhs, rhs, "should not be equal")
255    }
256
257    #[test]
258    fn should_be_able_to_default() {
259        let defaulted = ProtocolVersion::default();
260        let expected = ProtocolVersion::new(SemVer::new(0, 0, 0));
261        assert_eq!(defaulted, expected, "should be equal")
262    }
263
264    #[test]
265    fn should_be_able_to_compare_relative_value() {
266        let lhs = ProtocolVersion::new(SemVer::new(2, 0, 0));
267        let rhs = ProtocolVersion::new(SemVer::new(1, 0, 0));
268        assert!(lhs > rhs, "should be gt");
269        let rhs = ProtocolVersion::new(SemVer::new(2, 0, 0));
270        assert!(lhs >= rhs, "should be gte");
271        assert!(lhs <= rhs, "should be lte");
272        let lhs = ProtocolVersion::new(SemVer::new(1, 0, 0));
273        assert!(lhs < rhs, "should be lt");
274    }
275
276    #[test]
277    fn should_follow_major_version_upgrade() {
278        // If the upgrade protocol version is lower than or the same as EE's current in-use protocol
279        // version the upgrade is rejected and an error is returned; this includes the special case
280        // of a defaulted protocol version ( 0.0.0 ).
281        let prev = ProtocolVersion::new(SemVer::new(1, 0, 0));
282        let next = ProtocolVersion::new(SemVer::new(2, 0, 0));
283        assert!(
284            prev.check_next_version(&next).is_major_version(),
285            "should be major version"
286        );
287    }
288
289    #[test]
290    fn should_reject_if_major_version_decreases() {
291        let prev = ProtocolVersion::new(SemVer::new(10, 0, 0));
292        let next = ProtocolVersion::new(SemVer::new(9, 0, 0));
293        // Major version must not decrease ...
294        assert_eq!(prev.check_next_version(&next), VersionCheckResult::Invalid);
295    }
296
297    #[test]
298    fn should_check_follows_minor_version_upgrade() {
299        // [major version] may remain the same in the case of a minor or patch version increase.
300
301        // Minor version must not decrease within the same major version
302        let prev = ProtocolVersion::new(SemVer::new(1, 1, 0));
303        let next = ProtocolVersion::new(SemVer::new(1, 2, 0));
304
305        let value = prev.check_next_version(&next);
306        assert!(!value.is_invalid(), "should be valid");
307        assert!(!value.is_major_version(), "should not be a major version");
308    }
309
310    #[test]
311    fn should_not_care_if_minor_bump_resets_patch() {
312        let prev = ProtocolVersion::new(SemVer::new(1, 2, 0));
313        let next = ProtocolVersion::new(SemVer::new(1, 3, 1));
314        assert_eq!(
315            prev.check_next_version(&next),
316            VersionCheckResult::Valid {
317                is_major_version: false
318            }
319        );
320
321        let prev = ProtocolVersion::new(SemVer::new(1, 20, 42));
322        let next = ProtocolVersion::new(SemVer::new(1, 30, 43));
323        assert_eq!(
324            prev.check_next_version(&next),
325            VersionCheckResult::Valid {
326                is_major_version: false
327            }
328        );
329    }
330
331    #[test]
332    fn should_not_care_if_major_bump_resets_minor_or_patch() {
333        // A major version increase resets both the minor and patch versions to ( 0.0 ).
334        let prev = ProtocolVersion::new(SemVer::new(1, 0, 0));
335        let next = ProtocolVersion::new(SemVer::new(2, 1, 0));
336        assert_eq!(
337            prev.check_next_version(&next),
338            VersionCheckResult::Valid {
339                is_major_version: true
340            }
341        );
342
343        let next = ProtocolVersion::new(SemVer::new(2, 0, 1));
344        assert_eq!(
345            prev.check_next_version(&next),
346            VersionCheckResult::Valid {
347                is_major_version: true
348            }
349        );
350
351        let next = ProtocolVersion::new(SemVer::new(2, 1, 1));
352        assert_eq!(
353            prev.check_next_version(&next),
354            VersionCheckResult::Valid {
355                is_major_version: true
356            }
357        );
358    }
359
360    #[test]
361    fn should_reject_patch_version_rollback() {
362        // Patch version must not decrease or remain the same within the same major and minor
363        // version pair, but may skip.
364        let prev = ProtocolVersion::new(SemVer::new(1, 0, 42));
365        let next = ProtocolVersion::new(SemVer::new(1, 0, 41));
366        assert_eq!(prev.check_next_version(&next), VersionCheckResult::Invalid);
367        let next = ProtocolVersion::new(SemVer::new(1, 0, 13));
368        assert_eq!(prev.check_next_version(&next), VersionCheckResult::Invalid);
369    }
370
371    #[test]
372    fn should_accept_patch_version_update_with_optional_code() {
373        let prev = ProtocolVersion::new(SemVer::new(1, 0, 0));
374        let next = ProtocolVersion::new(SemVer::new(1, 0, 1));
375        let value = prev.check_next_version(&next);
376        assert!(!value.is_invalid(), "should be valid");
377        assert!(!value.is_major_version(), "should not be a major version");
378
379        let prev = ProtocolVersion::new(SemVer::new(1, 0, 8));
380        let next = ProtocolVersion::new(SemVer::new(1, 0, 42));
381        let value = prev.check_next_version(&next);
382        assert!(!value.is_invalid(), "should be valid");
383        assert!(!value.is_major_version(), "should not be a major version");
384    }
385
386    #[test]
387    fn should_accept_minor_version_update_with_optional_code() {
388        // installer is optional for minor bump
389        let prev = ProtocolVersion::new(SemVer::new(1, 0, 0));
390        let next = ProtocolVersion::new(SemVer::new(1, 1, 0));
391        let value = prev.check_next_version(&next);
392        assert!(!value.is_invalid(), "should be valid");
393        assert!(!value.is_major_version(), "should not be a major version");
394
395        let prev = ProtocolVersion::new(SemVer::new(3, 98, 0));
396        let next = ProtocolVersion::new(SemVer::new(3, 99, 0));
397        let value = prev.check_next_version(&next);
398        assert!(!value.is_invalid(), "should be valid");
399        assert!(!value.is_major_version(), "should not be a major version");
400    }
401
402    #[test]
403    fn should_allow_skip_minor_version_within_major_version() {
404        let prev = ProtocolVersion::new(SemVer::new(1, 1, 0));
405
406        let next = ProtocolVersion::new(SemVer::new(1, 3, 0));
407        assert_eq!(
408            prev.check_next_version(&next),
409            VersionCheckResult::Valid {
410                is_major_version: false
411            }
412        );
413
414        let next = ProtocolVersion::new(SemVer::new(1, 7, 0));
415        assert_eq!(
416            prev.check_next_version(&next),
417            VersionCheckResult::Valid {
418                is_major_version: false
419            }
420        );
421    }
422
423    #[test]
424    fn should_allow_skip_patch_version_within_minor_version() {
425        let prev = ProtocolVersion::new(SemVer::new(1, 1, 0));
426
427        let next = ProtocolVersion::new(SemVer::new(1, 1, 2));
428        assert_eq!(
429            prev.check_next_version(&next),
430            VersionCheckResult::Valid {
431                is_major_version: false
432            }
433        );
434    }
435
436    #[test]
437    fn should_allow_skipped_minor_and_patch_on_major_bump() {
438        // skip minor
439        let prev = ProtocolVersion::new(SemVer::new(1, 0, 0));
440        let next = ProtocolVersion::new(SemVer::new(2, 1, 0));
441        assert_eq!(
442            prev.check_next_version(&next),
443            VersionCheckResult::Valid {
444                is_major_version: true
445            }
446        );
447
448        // skip patch
449        let prev = ProtocolVersion::new(SemVer::new(1, 0, 0));
450        let next = ProtocolVersion::new(SemVer::new(2, 0, 1));
451        assert_eq!(
452            prev.check_next_version(&next),
453            VersionCheckResult::Valid {
454                is_major_version: true
455            }
456        );
457
458        // skip many minors and patches
459        let prev = ProtocolVersion::new(SemVer::new(1, 0, 0));
460        let next = ProtocolVersion::new(SemVer::new(2, 3, 10));
461        assert_eq!(
462            prev.check_next_version(&next),
463            VersionCheckResult::Valid {
464                is_major_version: true
465            }
466        );
467    }
468
469    #[test]
470    fn should_allow_code_on_major_update() {
471        // major upgrade requires installer to be present
472        let prev = ProtocolVersion::new(SemVer::new(1, 0, 0));
473        let next = ProtocolVersion::new(SemVer::new(2, 0, 0));
474        assert!(
475            prev.check_next_version(&next).is_major_version(),
476            "should be major version"
477        );
478
479        let prev = ProtocolVersion::new(SemVer::new(2, 99, 99));
480        let next = ProtocolVersion::new(SemVer::new(3, 0, 0));
481        assert!(
482            prev.check_next_version(&next).is_major_version(),
483            "should be major version"
484        );
485    }
486
487    #[test]
488    fn should_not_skip_major_version() {
489        // can bump only by 1
490        let prev = ProtocolVersion::new(SemVer::new(1, 0, 0));
491        let next = ProtocolVersion::new(SemVer::new(3, 0, 0));
492        assert_eq!(prev.check_next_version(&next), VersionCheckResult::Invalid);
493    }
494
495    #[test]
496    fn should_reject_major_version_rollback() {
497        // can bump forward
498        let prev = ProtocolVersion::new(SemVer::new(2, 0, 0));
499        let next = ProtocolVersion::new(SemVer::new(0, 0, 0));
500        assert_eq!(prev.check_next_version(&next), VersionCheckResult::Invalid);
501    }
502
503    #[test]
504    fn should_check_same_version_is_invalid() {
505        for ver in &[
506            ProtocolVersion::from_parts(1, 0, 0),
507            ProtocolVersion::from_parts(1, 2, 0),
508            ProtocolVersion::from_parts(1, 2, 3),
509        ] {
510            assert_eq!(ver.check_next_version(ver), VersionCheckResult::Invalid);
511        }
512    }
513
514    #[test]
515    fn should_not_be_compatible_with_different_major_version() {
516        let current = ProtocolVersion::from_parts(1, 2, 3);
517        let other = ProtocolVersion::from_parts(2, 5, 6);
518        assert!(!current.is_compatible_with(&other));
519
520        let current = ProtocolVersion::from_parts(1, 0, 0);
521        let other = ProtocolVersion::from_parts(2, 0, 0);
522        assert!(!current.is_compatible_with(&other));
523    }
524
525    #[test]
526    fn should_be_compatible_with_equal_major_version_backwards() {
527        let current = ProtocolVersion::from_parts(1, 99, 99);
528        let other = ProtocolVersion::from_parts(1, 0, 0);
529        assert!(current.is_compatible_with(&other));
530    }
531
532    #[test]
533    fn should_be_compatible_with_equal_major_version_forwards() {
534        let current = ProtocolVersion::from_parts(1, 0, 0);
535        let other = ProtocolVersion::from_parts(1, 99, 99);
536        assert!(current.is_compatible_with(&other));
537    }
538
539    #[test]
540    fn should_serialize_to_json_properly() {
541        let protocol_version = ProtocolVersion::from_parts(1, 1, 1);
542        let json = serde_json::to_string(&protocol_version).unwrap();
543        let expected = "\"1.1.1\"";
544        assert_eq!(json, expected);
545    }
546
547    #[test]
548    fn serialize_roundtrip() {
549        let protocol_version = ProtocolVersion::from_parts(1, 1, 1);
550        let serialized_json = serde_json::to_string(&protocol_version).unwrap();
551        assert_eq!(
552            protocol_version,
553            serde_json::from_str(&serialized_json).unwrap()
554        );
555
556        let serialized_bincode = bincode::serialize(&protocol_version).unwrap();
557        assert_eq!(
558            protocol_version,
559            bincode::deserialize(&serialized_bincode).unwrap()
560        );
561    }
562}