zebra_chain/parameters/
network.rs1use std::{fmt, str::FromStr, sync::Arc};
4
5use thiserror::Error;
6
7use crate::{
8 block::{self, Height},
9 parameters::NetworkUpgrade,
10};
11
12pub mod magic;
13pub mod subsidy;
14pub mod testnet;
15
16#[cfg(test)]
17mod tests;
18
19#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
24pub enum NetworkKind {
25 #[default]
27 Mainnet,
28
29 Testnet,
31
32 Regtest,
35}
36
37impl From<Network> for NetworkKind {
38 fn from(network: Network) -> Self {
39 network.kind()
40 }
41}
42
43#[derive(Clone, Default, Eq, PartialEq, Serialize)]
45#[serde(into = "NetworkKind")]
46pub enum Network {
47 #[default]
49 Mainnet,
50
51 Testnet(Arc<testnet::Parameters>),
54}
55
56impl NetworkKind {
57 pub fn b58_pubkey_address_prefix(self) -> [u8; 2] {
60 match self {
61 Self::Mainnet => zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX,
62 Self::Testnet | Self::Regtest => {
63 zcash_primitives::constants::testnet::B58_PUBKEY_ADDRESS_PREFIX
64 }
65 }
66 }
67
68 pub fn b58_script_address_prefix(self) -> [u8; 2] {
71 match self {
72 Self::Mainnet => zcash_primitives::constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX,
73 Self::Testnet | Self::Regtest => {
74 zcash_primitives::constants::testnet::B58_SCRIPT_ADDRESS_PREFIX
75 }
76 }
77 }
78
79 pub fn bip70_network_name(&self) -> String {
82 if *self == Self::Mainnet {
83 "main".to_string()
84 } else {
85 "test".to_string()
86 }
87 }
88}
89
90impl From<NetworkKind> for &'static str {
91 fn from(network: NetworkKind) -> &'static str {
92 match network {
96 NetworkKind::Mainnet => "MainnetKind",
97 NetworkKind::Testnet => "TestnetKind",
98 NetworkKind::Regtest => "RegtestKind",
99 }
100 }
101}
102
103impl fmt::Display for NetworkKind {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.write_str((*self).into())
106 }
107}
108
109impl<'a> From<&'a Network> for &'a str {
110 fn from(network: &'a Network) -> &'a str {
111 match network {
112 Network::Mainnet => "Mainnet",
113 Network::Testnet(params) => params.network_name(),
114 }
115 }
116}
117
118impl fmt::Display for Network {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 f.write_str(self.into())
121 }
122}
123
124impl std::fmt::Debug for Network {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 Self::Mainnet => write!(f, "{self}"),
128 Self::Testnet(params) if params.is_regtest() => f
129 .debug_struct("Regtest")
130 .field("activation_heights", params.activation_heights())
131 .finish(),
132 Self::Testnet(params) if params.is_default_testnet() => {
133 write!(f, "{self}")
134 }
135 Self::Testnet(params) => f.debug_tuple("ConfiguredTestnet").field(params).finish(),
136 }
137 }
138}
139
140impl Network {
141 pub fn new_default_testnet() -> Self {
143 Self::Testnet(Arc::new(testnet::Parameters::default()))
144 }
145
146 pub fn new_configured_testnet(params: testnet::Parameters) -> Self {
148 Self::Testnet(Arc::new(params))
149 }
150
151 pub fn new_regtest(
153 nu5_activation_height: Option<u32>,
154 nu6_activation_height: Option<u32>,
155 ) -> Self {
156 Self::new_configured_testnet(testnet::Parameters::new_regtest(
157 nu5_activation_height,
158 nu6_activation_height,
159 ))
160 }
161
162 pub fn is_default_testnet(&self) -> bool {
164 if let Self::Testnet(params) = self {
165 params.is_default_testnet()
166 } else {
167 false
168 }
169 }
170
171 pub fn is_regtest(&self) -> bool {
173 if let Self::Testnet(params) = self {
174 params.is_regtest()
175 } else {
176 false
177 }
178 }
179
180 pub fn kind(&self) -> NetworkKind {
182 match self {
183 Network::Mainnet => NetworkKind::Mainnet,
184 Network::Testnet(params) if params.is_regtest() => NetworkKind::Regtest,
185 Network::Testnet(_) => NetworkKind::Testnet,
186 }
187 }
188
189 pub fn iter() -> impl Iterator<Item = Self> {
191 [Self::Mainnet, Self::new_default_testnet()].into_iter()
192 }
193
194 pub fn is_max_block_time_enforced(&self, height: block::Height) -> bool {
203 match self {
204 Network::Mainnet => true,
205 Network::Testnet(_params) => height >= super::TESTNET_MAX_TIME_START_HEIGHT,
207 }
208 }
209
210 pub fn default_port(&self) -> u16 {
212 match self {
213 Network::Mainnet => 8233,
214 Network::Testnet(_params) => 18233,
216 }
217 }
218
219 pub fn mandatory_checkpoint_height(&self) -> Height {
229 NetworkUpgrade::Canopy
231 .activation_height(self)
232 .expect("Canopy activation height must be present on all networks")
233 .previous()
234 .expect("Canopy activation height must be above min height")
235 }
236
237 pub fn bip70_network_name(&self) -> String {
240 self.kind().bip70_network_name()
241 }
242
243 pub fn lowercase_name(&self) -> String {
245 self.to_string().to_ascii_lowercase()
246 }
247
248 pub fn is_a_test_network(&self) -> bool {
250 *self != Network::Mainnet
251 }
252
253 pub fn sapling_activation_height(&self) -> Height {
256 super::NetworkUpgrade::Sapling
257 .activation_height(self)
258 .expect("Sapling activation height needs to be set")
259 }
260}
261
262impl FromStr for Network {
264 type Err = InvalidNetworkError;
265
266 fn from_str(string: &str) -> Result<Self, Self::Err> {
267 match string.to_lowercase().as_str() {
268 "mainnet" => Ok(Network::Mainnet),
269 "testnet" => Ok(Network::new_default_testnet()),
270 _ => Err(InvalidNetworkError(string.to_owned())),
271 }
272 }
273}
274
275#[derive(Clone, Debug, Error)]
276#[error("Invalid network: {0}")]
277pub struct InvalidNetworkError(String);
278
279impl zcash_protocol::consensus::Parameters for Network {
280 fn network_type(&self) -> zcash_address::Network {
281 self.kind().into()
282 }
283
284 fn activation_height(
285 &self,
286 nu: zcash_protocol::consensus::NetworkUpgrade,
287 ) -> Option<zcash_protocol::consensus::BlockHeight> {
288 NetworkUpgrade::from(nu)
289 .activation_height(self)
290 .map(|Height(h)| zcash_protocol::consensus::BlockHeight::from_u32(h))
291 }
292}