mithril_common/entities/
cardano_network.rs

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