iota_types/
supported_protocol_versions.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::ops::RangeInclusive;
6
7use fastcrypto::hash::HashFunction;
8pub use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion};
9use serde::{Deserialize, Serialize};
10
11use crate::{crypto::DefaultHash, digests::Digest};
12
13/// Models the set of protocol versions supported by a validator.
14/// The `iota-node` binary will always use the SYSTEM_DEFAULT constant, but for
15/// testing we need to be able to inject arbitrary versions into IotaNode.
16#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
17pub struct SupportedProtocolVersions {
18    pub min: ProtocolVersion,
19    pub max: ProtocolVersion,
20}
21
22impl SupportedProtocolVersions {
23    pub const SYSTEM_DEFAULT: Self = Self {
24        min: ProtocolVersion::MIN,
25        max: ProtocolVersion::MAX,
26    };
27
28    pub fn new_for_testing(min: u64, max: u64) -> Self {
29        let min = min.into();
30        let max = max.into();
31        Self { min, max }
32    }
33
34    pub fn is_version_supported(&self, v: ProtocolVersion) -> bool {
35        v.as_u64() >= self.min.as_u64() && v.as_u64() <= self.max.as_u64()
36    }
37
38    pub fn as_range(&self) -> RangeInclusive<u64> {
39        self.min.as_u64()..=self.max.as_u64()
40    }
41
42    pub fn truncate_below(self, v: ProtocolVersion) -> Self {
43        let min = std::cmp::max(self.min, v);
44        Self { min, max: self.max }
45    }
46}
47
48/// Models the set of protocol versions supported by a validator.
49/// The `iota-node` binary will always use the SYSTEM_DEFAULT constant, but for
50/// testing we need to be able to inject arbitrary versions into IotaNode.
51#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
52pub struct SupportedProtocolVersionsWithHashes {
53    pub versions: Vec<(ProtocolVersion, Digest)>,
54}
55
56impl SupportedProtocolVersionsWithHashes {
57    pub fn get_version_digest(&self, v: ProtocolVersion) -> Option<Digest> {
58        self.versions
59            .iter()
60            .find(|(version, _)| *version == v)
61            .map(|(_, digest)| *digest)
62    }
63
64    // Ideally this would be in iota-protocol-config, but iota-types depends on
65    // iota-protocol-config, so it would introduce a circular dependency.
66    fn protocol_config_digest(config: &ProtocolConfig) -> Digest {
67        let mut digest = DefaultHash::default();
68        bcs::serialize_into(&mut digest, &config).expect("serialization cannot fail");
69        Digest::new(digest.finalize().into())
70    }
71
72    pub fn from_supported_versions(supported: SupportedProtocolVersions, chain: Chain) -> Self {
73        Self {
74            versions: supported
75                .as_range()
76                .map(|v| {
77                    (
78                        v.into(),
79                        Self::protocol_config_digest(&ProtocolConfig::get_for_version(
80                            v.into(),
81                            chain,
82                        )),
83                    )
84                })
85                .collect(),
86        }
87    }
88}