cardano_sdk/cardano/
network_id.rs

1//  This Source Code Form is subject to the terms of the Mozilla Public
2//  License, v. 2.0. If a copy of the MPL was not distributed with this
3//  file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use crate::{cbor, pallas};
6use anyhow::anyhow;
7use std::{fmt, str::FromStr};
8
9/// A network identifier to protect misuses of addresses or transactions on a wrong network.
10///
11/// Note that you can convert to and from [`u8`] using [`u8::from`] and [`Self::try_from`]
12/// respectively.:
13///
14/// ```rust
15/// # use cardano_sdk::{NetworkId};
16/// assert_eq!(u8::from(NetworkId::TESTNET), 0);
17/// assert_eq!(u8::from(NetworkId::MAINNET), 1);
18/// ```
19///
20/// ```rust
21/// # use cardano_sdk::{NetworkId};
22/// assert!(NetworkId::try_from(0_u8).is_ok_and(|network| network.is_testnet()));
23/// assert!(NetworkId::try_from(1_u8).is_ok_and(|network| network.is_mainnet()));
24/// ```
25#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, cbor::Encode, cbor::Decode)]
26#[repr(transparent)]
27#[cbor(transparent)]
28pub struct NetworkId(#[n(0)] pallas::NetworkId);
29
30impl fmt::Display for NetworkId {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
32        f.write_str(match self.0 {
33            pallas::NetworkId::Testnet => "testnet",
34            pallas::NetworkId::Mainnet => "mainnet",
35        })
36    }
37}
38
39// -------------------------------------------------------------------- Building
40
41impl NetworkId {
42    pub const MAINNET: Self = Self(pallas::NetworkId::Mainnet);
43    pub const TESTNET: Self = Self(pallas::NetworkId::Testnet);
44}
45
46// ------------------------------------------------------------------ Inspecting
47
48impl NetworkId {
49    pub fn is_mainnet(&self) -> bool {
50        self.0 == pallas::NetworkId::Mainnet
51    }
52
53    pub fn is_testnet(&self) -> bool {
54        self.0 == pallas::NetworkId::Testnet
55    }
56}
57
58// ----------------------------------------------------------- Converting (from)
59
60impl FromStr for NetworkId {
61    type Err = anyhow::Error;
62
63    fn from_str(s: &str) -> anyhow::Result<Self> {
64        match s {
65            _ if s == Self::MAINNET.to_string() => Ok(Self::MAINNET),
66            _ if s == Self::TESTNET.to_string() => Ok(Self::TESTNET),
67            _ => Err(anyhow!(
68                "unrecognised network id: must be either 'mainnet' or 'testnet'"
69            )),
70        }
71    }
72}
73
74impl From<pallas::NetworkId> for NetworkId {
75    fn from(network_id: pallas::NetworkId) -> Self {
76        Self(network_id)
77    }
78}
79
80impl From<pallas::Network> for NetworkId {
81    fn from(network: pallas::Network) -> Self {
82        match network {
83            pallas_addresses::Network::Mainnet => Self(pallas::NetworkId::Mainnet),
84            pallas_addresses::Network::Testnet | pallas_addresses::Network::Other(..) => {
85                Self(pallas::NetworkId::Testnet)
86            }
87        }
88    }
89}
90
91impl TryFrom<u8> for NetworkId {
92    type Error = anyhow::Error;
93
94    fn try_from(i: u8) -> anyhow::Result<Self> {
95        pallas::NetworkId::try_from(i)
96            .map_err(|()| anyhow!("invalid network identifer; expected either 0 or 1"))
97            .map(NetworkId)
98    }
99}
100
101// ------------------------------------------------------------- Converting (to)
102
103impl From<NetworkId> for pallas::NetworkId {
104    fn from(network_id: NetworkId) -> Self {
105        network_id.0
106    }
107}
108
109impl From<NetworkId> for pallas::Network {
110    fn from(network_id: NetworkId) -> Self {
111        match network_id.0 {
112            pallas::NetworkId::Mainnet => pallas::Network::Mainnet,
113            pallas::NetworkId::Testnet => pallas::Network::Testnet,
114        }
115    }
116}
117
118impl From<NetworkId> for u8 {
119    fn from(network_id: NetworkId) -> u8 {
120        u8::from(network_id.0)
121    }
122}
123
124#[cfg(any(test, feature = "test-utils"))]
125pub mod tests {
126    use crate::NetworkId;
127    use proptest::prelude::*;
128
129    // -------------------------------------------------------------- Unit tests
130
131    #[test]
132    fn display_testnet() {
133        assert_eq!(NetworkId::TESTNET.to_string(), "testnet")
134    }
135
136    #[test]
137    fn display_mainnet() {
138        assert_eq!(NetworkId::MAINNET.to_string(), "mainnet")
139    }
140
141    // -------------------------------------------------------------- Generators
142
143    pub mod generators {
144        use super::*;
145
146        prop_compose! {
147            pub fn network_id()(is_testnet in any::<bool>()) -> NetworkId {
148                if is_testnet {
149                    NetworkId::TESTNET
150                } else {
151                    NetworkId::MAINNET
152                }
153            }
154        }
155    }
156}