mithril_common/entities/
cardano_network.rs

1use serde::{Deserialize, Serialize};
2use std::fmt::Display;
3use thiserror::Error;
4
5use crate::{MagicId, StdResult};
6
7#[derive(Error, Debug)]
8pub enum CardanoNetworkError {
9    #[error("parse from code error: '{0}'")]
10    ParseFromCode(String),
11}
12
13/// The Cardano Network that is being targeted
14#[allow(clippy::enum_variant_names)]
15#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, Hash, Eq, PartialOrd)]
16pub enum CardanoNetwork {
17    /// The Cardano mainnet network
18    MainNet,
19
20    /// A Cardano test network (preview, preprod or private testnet)
21    TestNet(MagicId),
22}
23
24impl CardanoNetwork {
25    /// Mainnet magic ID
26    pub const MAINNET_MAGIC_ID: MagicId = 764824073;
27    /// Preprod magic ID
28    pub const PREPROD_MAGIC_ID: MagicId = 1;
29    /// Preview magic ID
30    pub const PREVIEW_MAGIC_ID: MagicId = 2;
31    /// Devnet magic ID
32    pub(crate) const DEVNET_MAGIC_ID: MagicId = 42;
33
34    /// Instantiates a CardanoNetwork from its code and magic id
35    pub fn from_code(
36        network_code: String,
37        network_magic: Option<u64>,
38    ) -> Result<CardanoNetwork, CardanoNetworkError> {
39        match network_code.to_lowercase().as_str() {
40            "mainnet" => Ok(CardanoNetwork::MainNet),
41            "preview" => Ok(CardanoNetwork::TestNet(Self::PREVIEW_MAGIC_ID)),
42            "preprod" => Ok(CardanoNetwork::TestNet(Self::PREPROD_MAGIC_ID)),
43            "devnet" => Ok(CardanoNetwork::TestNet(Self::DEVNET_MAGIC_ID)),
44            "private" => {
45                if let Some(magic) = network_magic {
46                    Ok(CardanoNetwork::TestNet(magic))
47                } else {
48                    Err(CardanoNetworkError::ParseFromCode(
49                        "no NETWORK MAGIC number given for test network".to_string(),
50                    ))
51                }
52            }
53            what => Err(CardanoNetworkError::ParseFromCode(format!(
54                "could not parse network '{what}', the only recognized networks are: mainnet, devnet, testnet, preview, preprod and private"
55            ))),
56        }
57    }
58
59    /// Returns the magic ID of the network
60    pub fn magic_id(&self) -> MagicId {
61        match *self {
62            CardanoNetwork::MainNet => Self::MAINNET_MAGIC_ID,
63            CardanoNetwork::TestNet(magic_id) => magic_id,
64        }
65    }
66
67    /// Determines whether unparsable blocks should be allowed based on the specific Cardano network.
68    pub fn compute_allow_unparsable_block(&self, allow_unparsable_block: bool) -> StdResult<bool> {
69        let allow_unparsable_block = match self {
70            CardanoNetwork::MainNet => false,
71            CardanoNetwork::TestNet(id) if *id == Self::PREPROD_MAGIC_ID => false,
72            _ => allow_unparsable_block,
73        };
74
75        Ok(allow_unparsable_block)
76    }
77}
78
79impl Display for CardanoNetwork {
80    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81        match *self {
82            CardanoNetwork::MainNet => write!(f, "mainnet"),
83            CardanoNetwork::TestNet(magic_id) => match magic_id {
84                Self::PREVIEW_MAGIC_ID => write!(f, "preview"),
85                Self::PREPROD_MAGIC_ID => write!(f, "preprod"),
86                Self::DEVNET_MAGIC_ID => write!(f, "devnet"),
87                _ => write!(f, "private"),
88            },
89        }
90    }
91}
92
93impl From<CardanoNetwork> for String {
94    fn from(network: CardanoNetwork) -> Self {
95        network.to_string()
96    }
97}
98
99impl From<&CardanoNetwork> for String {
100    fn from(network: &CardanoNetwork) -> Self {
101        network.to_string()
102    }
103}
104
105impl From<MagicId> for CardanoNetwork {
106    fn from(magic_id: MagicId) -> Self {
107        match magic_id {
108            Self::MAINNET_MAGIC_ID => Self::MainNet,
109            _ => Self::TestNet(magic_id),
110        }
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_cardano_network_from_code() {
120        assert_eq!(
121            CardanoNetwork::from_code("mainnet".to_string(), None).unwrap(),
122            CardanoNetwork::MainNet
123        );
124        assert_eq!(
125            CardanoNetwork::from_code("mainnet".to_string(), Some(123)).unwrap(),
126            CardanoNetwork::MainNet
127        );
128        assert_eq!(
129            CardanoNetwork::from_code("preview".to_string(), None).unwrap(),
130            CardanoNetwork::TestNet(CardanoNetwork::PREVIEW_MAGIC_ID)
131        );
132        assert_eq!(
133            CardanoNetwork::from_code("preview".to_string(), Some(123)).unwrap(),
134            CardanoNetwork::TestNet(CardanoNetwork::PREVIEW_MAGIC_ID)
135        );
136        assert_eq!(
137            CardanoNetwork::from_code("preprod".to_string(), None).unwrap(),
138            CardanoNetwork::TestNet(CardanoNetwork::PREPROD_MAGIC_ID)
139        );
140        assert_eq!(
141            CardanoNetwork::from_code("preprod".to_string(), Some(123)).unwrap(),
142            CardanoNetwork::TestNet(CardanoNetwork::PREPROD_MAGIC_ID)
143        );
144        assert_eq!(
145            CardanoNetwork::from_code("devnet".to_string(), None).unwrap(),
146            CardanoNetwork::TestNet(CardanoNetwork::DEVNET_MAGIC_ID)
147        );
148        assert_eq!(
149            CardanoNetwork::from_code("devnet".to_string(), Some(123)).unwrap(),
150            CardanoNetwork::TestNet(CardanoNetwork::DEVNET_MAGIC_ID)
151        );
152        assert_eq!(
153            CardanoNetwork::from_code("private".to_string(), Some(123)).unwrap(),
154            CardanoNetwork::TestNet(123)
155        );
156        assert!(CardanoNetwork::from_code("private".to_string(), None).is_err());
157    }
158
159    #[test]
160    fn compute_allow_unparsable_block_should_always_return_false_on_mainnet_and_preprod() {
161        let allow_unparsable_block =
162            CardanoNetwork::MainNet.compute_allow_unparsable_block(false).unwrap();
163        assert!(!allow_unparsable_block);
164
165        let allow_unparsable_block =
166            CardanoNetwork::MainNet.compute_allow_unparsable_block(true).unwrap();
167        assert!(!allow_unparsable_block);
168
169        let allow_unparsable_block = CardanoNetwork::TestNet(CardanoNetwork::PREPROD_MAGIC_ID)
170            .compute_allow_unparsable_block(false)
171            .unwrap();
172        assert!(!allow_unparsable_block);
173
174        let allow_unparsable_block = CardanoNetwork::TestNet(CardanoNetwork::PREPROD_MAGIC_ID)
175            .compute_allow_unparsable_block(true)
176            .unwrap();
177        assert!(!allow_unparsable_block);
178    }
179
180    #[test]
181    fn compute_allow_unparsable_block_should_return_value_passed_in_parameter_on_all_networks_other_than_mainnet_and_preprod()
182     {
183        let allow_unparsable_block = CardanoNetwork::TestNet(CardanoNetwork::PREVIEW_MAGIC_ID)
184            .compute_allow_unparsable_block(false)
185            .unwrap();
186        assert!(!allow_unparsable_block);
187
188        let allow_unparsable_block = CardanoNetwork::TestNet(CardanoNetwork::PREVIEW_MAGIC_ID)
189            .compute_allow_unparsable_block(true)
190            .unwrap();
191        assert!(allow_unparsable_block);
192
193        let allow_unparsable_block = CardanoNetwork::TestNet(CardanoNetwork::DEVNET_MAGIC_ID)
194            .compute_allow_unparsable_block(false)
195            .unwrap();
196        assert!(!allow_unparsable_block);
197
198        let allow_unparsable_block = CardanoNetwork::TestNet(CardanoNetwork::DEVNET_MAGIC_ID)
199            .compute_allow_unparsable_block(true)
200            .unwrap();
201        assert!(allow_unparsable_block);
202
203        let allow_unparsable_block = CardanoNetwork::TestNet(123)
204            .compute_allow_unparsable_block(false)
205            .unwrap();
206        assert!(!allow_unparsable_block);
207
208        let allow_unparsable_block = CardanoNetwork::TestNet(123)
209            .compute_allow_unparsable_block(true)
210            .unwrap();
211        assert!(allow_unparsable_block);
212    }
213
214    #[test]
215    fn network_to_string() {
216        fn assert_all_conversions_eq(network: CardanoNetwork, expected: &str) {
217            assert_eq!(network.to_string(), expected);
218            assert_eq!(String::from(network), expected);
219            assert_eq!(String::from(&network), expected);
220        }
221
222        assert_all_conversions_eq(CardanoNetwork::MainNet, "mainnet");
223        assert_all_conversions_eq(
224            CardanoNetwork::TestNet(CardanoNetwork::DEVNET_MAGIC_ID),
225            "devnet",
226        );
227        assert_all_conversions_eq(
228            CardanoNetwork::TestNet(CardanoNetwork::PREVIEW_MAGIC_ID),
229            "preview",
230        );
231        assert_all_conversions_eq(
232            CardanoNetwork::TestNet(CardanoNetwork::PREPROD_MAGIC_ID),
233            "preprod",
234        );
235        assert_all_conversions_eq(CardanoNetwork::TestNet(123456), "private");
236    }
237
238    #[test]
239    fn cardano_network_from_magic_id_roundtrip() {
240        fn assert_magic_id_conversion_roundtrip(magic_id: MagicId, expected: CardanoNetwork) {
241            let network = CardanoNetwork::from(magic_id);
242            assert_eq!(network, expected);
243            assert_eq!(network.magic_id(), magic_id);
244        }
245
246        assert_magic_id_conversion_roundtrip(
247            CardanoNetwork::MAINNET_MAGIC_ID,
248            CardanoNetwork::MainNet,
249        );
250        assert_magic_id_conversion_roundtrip(
251            CardanoNetwork::PREVIEW_MAGIC_ID,
252            CardanoNetwork::TestNet(CardanoNetwork::PREVIEW_MAGIC_ID),
253        );
254        assert_magic_id_conversion_roundtrip(
255            CardanoNetwork::PREPROD_MAGIC_ID,
256            CardanoNetwork::TestNet(CardanoNetwork::PREPROD_MAGIC_ID),
257        );
258        assert_magic_id_conversion_roundtrip(
259            CardanoNetwork::DEVNET_MAGIC_ID,
260            CardanoNetwork::TestNet(CardanoNetwork::DEVNET_MAGIC_ID),
261        );
262        assert_magic_id_conversion_roundtrip(123456, CardanoNetwork::TestNet(123456));
263    }
264}