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#[allow(clippy::enum_variant_names)]
15#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, Hash, Eq, PartialOrd)]
16pub enum CardanoNetwork {
17 MainNet,
19
20 TestNet(MagicId),
22}
23
24impl CardanoNetwork {
25 pub const MAINNET_MAGIC_ID: MagicId = 764824073;
27 pub const PREPROD_MAGIC_ID: MagicId = 1;
29 pub const PREVIEW_MAGIC_ID: MagicId = 2;
31 pub(crate) const DEVNET_MAGIC_ID: MagicId = 42;
33
34 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 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 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}