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#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
17#[cfg_attr(feature = "datasize", derive(DataSize))]
18pub struct ProtocolVersion(SemVer);
19
20#[derive(Debug, PartialEq, Eq)]
22pub enum VersionCheckResult {
23 Valid {
25 is_major_version: bool,
27 },
28 Invalid,
30}
31
32impl VersionCheckResult {
33 pub fn is_invalid(&self) -> bool {
37 matches!(self, VersionCheckResult::Invalid)
38 }
39
40 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 pub const V1_0_0: ProtocolVersion = ProtocolVersion(SemVer {
52 major: 1,
53 minor: 0,
54 patch: 0,
55 });
56
57 pub const V2_0_0: ProtocolVersion = ProtocolVersion(SemVer {
59 major: 2,
60 minor: 0,
61 patch: 0,
62 });
63
64 pub const fn new(version: SemVer) -> ProtocolVersion {
66 ProtocolVersion(version)
67 }
68
69 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 pub const fn value(&self) -> SemVer {
77 self.0
78 }
79
80 pub const fn destructure(&self) -> (u32, u32, u32) {
82 (self.0.major, self.0.minor, self.0.patch)
83 }
84
85 pub fn check_next_version(&self, next: &ProtocolVersion) -> VersionCheckResult {
87 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 debug_assert_eq!(next.0.major, self.0.major);
101
102 if next.0.minor < self.0.minor {
103 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 debug_assert_eq!(next.0.minor, self.0.minor);
115
116 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 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 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 assert_eq!(prev.check_next_version(&next), VersionCheckResult::Invalid);
295 }
296
297 #[test]
298 fn should_check_follows_minor_version_upgrade() {
299 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 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 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 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 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 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 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 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 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 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}