zebra_chain/parameters/
network.rs1use std::{fmt, str::FromStr, sync::Arc};
4
5use thiserror::Error;
6
7use crate::{
8 amount::{Amount, NonNegative},
9 block::{self, Height},
10 parameters::NetworkUpgrade,
11 transparent,
12};
13
14mod error;
15pub mod magic;
16pub mod subsidy;
17pub mod testnet;
18
19#[cfg(test)]
20mod tests;
21
22#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
27pub enum NetworkKind {
28 #[default]
30 Mainnet,
31
32 Testnet,
34
35 Regtest,
37}
38
39impl From<Network> for NetworkKind {
40 fn from(net: Network) -> Self {
41 NetworkKind::from(&net)
42 }
43}
44
45impl From<&Network> for NetworkKind {
46 fn from(net: &Network) -> Self {
47 net.kind()
48 }
49}
50
51#[derive(Clone, Default, Eq, PartialEq, Serialize)]
53#[serde(into = "NetworkKind")]
54pub enum Network {
55 #[default]
57 Mainnet,
58
59 Testnet(Arc<testnet::Parameters>),
62}
63
64impl NetworkKind {
65 pub fn b58_pubkey_address_prefix(self) -> [u8; 2] {
68 match self {
69 Self::Mainnet => zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX,
70 Self::Testnet | Self::Regtest => {
71 zcash_primitives::constants::testnet::B58_PUBKEY_ADDRESS_PREFIX
72 }
73 }
74 }
75
76 pub fn b58_script_address_prefix(self) -> [u8; 2] {
79 match self {
80 Self::Mainnet => zcash_primitives::constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX,
81 Self::Testnet | Self::Regtest => {
82 zcash_primitives::constants::testnet::B58_SCRIPT_ADDRESS_PREFIX
83 }
84 }
85 }
86
87 pub fn bip70_network_name(&self) -> String {
90 if *self == Self::Mainnet {
91 "main".to_string()
92 } else {
93 "test".to_string()
94 }
95 }
96
97 pub fn tex_address_prefix(self) -> [u8; 2] {
100 match self {
102 Self::Mainnet => [0x1c, 0xb8],
103 Self::Testnet | Self::Regtest => [0x1d, 0x25],
104 }
105 }
106}
107
108impl From<NetworkKind> for &'static str {
109 fn from(network: NetworkKind) -> &'static str {
110 match network {
114 NetworkKind::Mainnet => "MainnetKind",
115 NetworkKind::Testnet => "TestnetKind",
116 NetworkKind::Regtest => "RegtestKind",
117 }
118 }
119}
120
121impl fmt::Display for NetworkKind {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 f.write_str((*self).into())
124 }
125}
126
127impl<'a> From<&'a Network> for &'a str {
128 fn from(network: &'a Network) -> &'a str {
129 match network {
130 Network::Mainnet => "Mainnet",
131 Network::Testnet(params) => params.network_name(),
132 }
133 }
134}
135
136impl fmt::Display for Network {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.write_str(self.into())
139 }
140}
141
142impl std::fmt::Debug for Network {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 match self {
145 Self::Mainnet => write!(f, "{self}"),
146 Self::Testnet(params) if params.is_regtest() => f
147 .debug_struct("Regtest")
148 .field("activation_heights", params.activation_heights())
149 .field("funding_streams", params.funding_streams())
150 .field("lockbox_disbursements", ¶ms.lockbox_disbursements())
151 .field("checkpoints", ¶ms.checkpoints())
152 .finish(),
153 Self::Testnet(params) if params.is_default_testnet() => {
154 write!(f, "{self}")
155 }
156 Self::Testnet(params) => f.debug_tuple("ConfiguredTestnet").field(params).finish(),
157 }
158 }
159}
160
161impl Network {
162 pub fn new_default_testnet() -> Self {
164 Self::Testnet(Arc::new(testnet::Parameters::default()))
165 }
166
167 pub fn new_configured_testnet(params: testnet::Parameters) -> Self {
169 Self::Testnet(Arc::new(params))
170 }
171
172 pub fn new_regtest(params: testnet::RegtestParameters) -> Self {
174 Self::new_configured_testnet(
175 testnet::Parameters::new_regtest(params)
176 .expect("regtest parameters should always be valid"),
177 )
178 }
179
180 pub fn is_default_testnet(&self) -> bool {
182 if let Self::Testnet(params) = self {
183 params.is_default_testnet()
184 } else {
185 false
186 }
187 }
188
189 pub fn is_regtest(&self) -> bool {
191 if let Self::Testnet(params) = self {
192 params.is_regtest()
193 } else {
194 false
195 }
196 }
197
198 pub fn kind(&self) -> NetworkKind {
200 match self {
201 Network::Mainnet => NetworkKind::Mainnet,
202 Network::Testnet(params) if params.is_regtest() => NetworkKind::Regtest,
203 Network::Testnet(_) => NetworkKind::Testnet,
204 }
205 }
206
207 pub fn t_addr_kind(&self) -> NetworkKind {
211 match self {
212 Network::Mainnet => NetworkKind::Mainnet,
213 Network::Testnet(_) => NetworkKind::Testnet,
214 }
215 }
216
217 pub fn iter() -> impl Iterator<Item = Self> {
219 [Self::Mainnet, Self::new_default_testnet()].into_iter()
220 }
221
222 pub fn is_max_block_time_enforced(&self, height: block::Height) -> bool {
231 match self {
232 Network::Mainnet => true,
233 Network::Testnet(_params) => height >= super::TESTNET_MAX_TIME_START_HEIGHT,
235 }
236 }
237
238 pub fn default_port(&self) -> u16 {
240 match self {
241 Network::Mainnet => 8233,
242 Network::Testnet(_params) => 18233,
244 }
245 }
246
247 pub fn mandatory_checkpoint_height(&self) -> Height {
257 NetworkUpgrade::Canopy
259 .activation_height(self)
260 .expect("Canopy activation height must be present on all networks")
261 .previous()
262 .expect("Canopy activation height must be above min height")
263 }
264
265 pub fn bip70_network_name(&self) -> String {
268 self.kind().bip70_network_name()
269 }
270
271 pub fn lowercase_name(&self) -> String {
273 self.to_string().to_ascii_lowercase()
274 }
275
276 pub fn is_a_test_network(&self) -> bool {
278 *self != Network::Mainnet
279 }
280
281 pub fn sapling_activation_height(&self) -> Height {
284 super::NetworkUpgrade::Sapling
285 .activation_height(self)
286 .expect("Sapling activation height needs to be set")
287 }
288
289 pub fn lockbox_disbursement_total_amount(&self, height: Height) -> Amount<NonNegative> {
292 if Some(height) != NetworkUpgrade::Nu6_1.activation_height(self) {
293 return Amount::zero();
294 };
295
296 match self {
297 Self::Mainnet => subsidy::EXPECTED_NU6_1_LOCKBOX_DISBURSEMENTS_TOTAL_MAINNET,
298 Self::Testnet(params) if params.is_default_testnet() => {
299 subsidy::EXPECTED_NU6_1_LOCKBOX_DISBURSEMENTS_TOTAL_TESTNET
300 }
301 Self::Testnet(params) => params.lockbox_disbursement_total_amount(),
302 }
303 }
304
305 pub fn lockbox_disbursements(
307 &self,
308 height: Height,
309 ) -> Vec<(transparent::Address, Amount<NonNegative>)> {
310 if Some(height) != NetworkUpgrade::Nu6_1.activation_height(self) {
311 return Vec::new();
312 };
313
314 let expected_lockbox_disbursements = match self {
315 Self::Mainnet => subsidy::NU6_1_LOCKBOX_DISBURSEMENTS_MAINNET.to_vec(),
316 Self::Testnet(params) if params.is_default_testnet() => {
317 subsidy::NU6_1_LOCKBOX_DISBURSEMENTS_TESTNET.to_vec()
318 }
319 Self::Testnet(params) => return params.lockbox_disbursements(),
320 };
321
322 expected_lockbox_disbursements
323 .into_iter()
324 .map(|(addr, amount)| {
325 (
326 addr.parse().expect("hard-coded address must deserialize"),
327 amount,
328 )
329 })
330 .collect()
331 }
332}
333
334impl FromStr for Network {
336 type Err = InvalidNetworkError;
337
338 fn from_str(string: &str) -> Result<Self, Self::Err> {
339 match string.to_lowercase().as_str() {
340 "mainnet" => Ok(Network::Mainnet),
341 "testnet" => Ok(Network::new_default_testnet()),
342 _ => Err(InvalidNetworkError(string.to_owned())),
343 }
344 }
345}
346
347#[derive(Clone, Debug, Error)]
348#[error("Invalid network: {0}")]
349pub struct InvalidNetworkError(String);
350
351impl zcash_protocol::consensus::Parameters for Network {
352 fn network_type(&self) -> zcash_protocol::consensus::NetworkType {
353 self.kind().into()
354 }
355
356 fn activation_height(
357 &self,
358 nu: zcash_protocol::consensus::NetworkUpgrade,
359 ) -> Option<zcash_protocol::consensus::BlockHeight> {
360 NetworkUpgrade::from(nu)
361 .activation_height(self)
362 .map(|Height(h)| zcash_protocol::consensus::BlockHeight::from_u32(h))
363 }
364}