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
14pub mod magic;
15pub mod subsidy;
16pub mod testnet;
17
18#[cfg(test)]
19mod tests;
20
21#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
26pub enum NetworkKind {
27 #[default]
29 Mainnet,
30
31 Testnet,
33
34 Regtest,
36}
37
38impl From<Network> for NetworkKind {
39 fn from(net: Network) -> Self {
40 NetworkKind::from(&net)
41 }
42}
43
44impl From<&Network> for NetworkKind {
45 fn from(net: &Network) -> Self {
46 net.kind()
47 }
48}
49
50#[derive(Clone, Default, Eq, PartialEq, Serialize)]
52#[serde(into = "NetworkKind")]
53pub enum Network {
54 #[default]
56 Mainnet,
57
58 Testnet(Arc<testnet::Parameters>),
61}
62
63impl NetworkKind {
64 pub fn b58_pubkey_address_prefix(self) -> [u8; 2] {
67 match self {
68 Self::Mainnet => zcash_primitives::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX,
69 Self::Testnet | Self::Regtest => {
70 zcash_primitives::constants::testnet::B58_PUBKEY_ADDRESS_PREFIX
71 }
72 }
73 }
74
75 pub fn b58_script_address_prefix(self) -> [u8; 2] {
78 match self {
79 Self::Mainnet => zcash_primitives::constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX,
80 Self::Testnet | Self::Regtest => {
81 zcash_primitives::constants::testnet::B58_SCRIPT_ADDRESS_PREFIX
82 }
83 }
84 }
85
86 pub fn bip70_network_name(&self) -> String {
89 if *self == Self::Mainnet {
90 "main".to_string()
91 } else {
92 "test".to_string()
93 }
94 }
95
96 pub fn tex_address_prefix(self) -> [u8; 2] {
99 match self {
101 Self::Mainnet => [0x1c, 0xb8],
102 Self::Testnet | Self::Regtest => [0x1d, 0x25],
103 }
104 }
105}
106
107impl From<NetworkKind> for &'static str {
108 fn from(network: NetworkKind) -> &'static str {
109 match network {
113 NetworkKind::Mainnet => "MainnetKind",
114 NetworkKind::Testnet => "TestnetKind",
115 NetworkKind::Regtest => "RegtestKind",
116 }
117 }
118}
119
120impl fmt::Display for NetworkKind {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 f.write_str((*self).into())
123 }
124}
125
126impl<'a> From<&'a Network> for &'a str {
127 fn from(network: &'a Network) -> &'a str {
128 match network {
129 Network::Mainnet => "Mainnet",
130 Network::Testnet(params) => params.network_name(),
131 }
132 }
133}
134
135impl fmt::Display for Network {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.write_str(self.into())
138 }
139}
140
141impl std::fmt::Debug for Network {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 match self {
144 Self::Mainnet => write!(f, "{self}"),
145 Self::Testnet(params) if params.is_regtest() => f
146 .debug_struct("Regtest")
147 .field("activation_heights", params.activation_heights())
148 .field("funding_streams", params.funding_streams())
149 .finish(),
150 Self::Testnet(params) if params.is_default_testnet() => {
151 write!(f, "{self}")
152 }
153 Self::Testnet(params) => f.debug_tuple("ConfiguredTestnet").field(params).finish(),
154 }
155 }
156}
157
158impl Network {
159 pub fn new_default_testnet() -> Self {
161 Self::Testnet(Arc::new(testnet::Parameters::default()))
162 }
163
164 pub fn new_configured_testnet(params: testnet::Parameters) -> Self {
166 Self::Testnet(Arc::new(params))
167 }
168
169 pub fn new_regtest(params: testnet::RegtestParameters) -> Self {
171 Self::new_configured_testnet(testnet::Parameters::new_regtest(params))
172 }
173
174 pub fn is_default_testnet(&self) -> bool {
176 if let Self::Testnet(params) = self {
177 params.is_default_testnet()
178 } else {
179 false
180 }
181 }
182
183 pub fn is_regtest(&self) -> bool {
185 if let Self::Testnet(params) = self {
186 params.is_regtest()
187 } else {
188 false
189 }
190 }
191
192 pub fn kind(&self) -> NetworkKind {
194 match self {
195 Network::Mainnet => NetworkKind::Mainnet,
196 Network::Testnet(params) if params.is_regtest() => NetworkKind::Regtest,
197 Network::Testnet(_) => NetworkKind::Testnet,
198 }
199 }
200
201 pub fn t_addr_kind(&self) -> NetworkKind {
205 match self {
206 Network::Mainnet => NetworkKind::Mainnet,
207 Network::Testnet(_) => NetworkKind::Testnet,
208 }
209 }
210
211 pub fn iter() -> impl Iterator<Item = Self> {
213 [Self::Mainnet, Self::new_default_testnet()].into_iter()
214 }
215
216 pub fn is_max_block_time_enforced(&self, height: block::Height) -> bool {
225 match self {
226 Network::Mainnet => true,
227 Network::Testnet(_params) => height >= super::TESTNET_MAX_TIME_START_HEIGHT,
229 }
230 }
231
232 pub fn default_port(&self) -> u16 {
234 match self {
235 Network::Mainnet => 8233,
236 Network::Testnet(_params) => 18233,
238 }
239 }
240
241 pub fn mandatory_checkpoint_height(&self) -> Height {
251 NetworkUpgrade::Canopy
253 .activation_height(self)
254 .expect("Canopy activation height must be present on all networks")
255 .previous()
256 .expect("Canopy activation height must be above min height")
257 }
258
259 pub fn bip70_network_name(&self) -> String {
262 self.kind().bip70_network_name()
263 }
264
265 pub fn lowercase_name(&self) -> String {
267 self.to_string().to_ascii_lowercase()
268 }
269
270 pub fn is_a_test_network(&self) -> bool {
272 *self != Network::Mainnet
273 }
274
275 pub fn sapling_activation_height(&self) -> Height {
278 super::NetworkUpgrade::Sapling
279 .activation_height(self)
280 .expect("Sapling activation height needs to be set")
281 }
282
283 pub fn lockbox_disbursement_total_amount(&self, height: Height) -> Amount<NonNegative> {
286 if Some(height) != NetworkUpgrade::Nu6_1.activation_height(self) {
287 return Amount::zero();
288 };
289
290 match self {
291 Self::Mainnet => subsidy::EXPECTED_NU6_1_LOCKBOX_DISBURSEMENTS_TOTAL_MAINNET,
292 Self::Testnet(params) if params.is_default_testnet() => {
293 subsidy::EXPECTED_NU6_1_LOCKBOX_DISBURSEMENTS_TOTAL_TESTNET
294 }
295 Self::Testnet(params) => params.lockbox_disbursement_total_amount(),
296 }
297 }
298
299 pub fn lockbox_disbursements(
301 &self,
302 height: Height,
303 ) -> Vec<(transparent::Address, Amount<NonNegative>)> {
304 if Some(height) != NetworkUpgrade::Nu6_1.activation_height(self) {
305 return Vec::new();
306 };
307
308 let expected_lockbox_disbursements = match self {
309 Self::Mainnet => subsidy::NU6_1_LOCKBOX_DISBURSEMENTS_MAINNET.to_vec(),
310 Self::Testnet(params) if params.is_default_testnet() => {
311 subsidy::NU6_1_LOCKBOX_DISBURSEMENTS_TESTNET.to_vec()
312 }
313 Self::Testnet(params) => return params.lockbox_disbursements(),
314 };
315
316 expected_lockbox_disbursements
317 .into_iter()
318 .map(|(addr, amount)| {
319 (
320 addr.parse().expect("hard-coded address must deserialize"),
321 amount,
322 )
323 })
324 .collect()
325 }
326}
327
328impl FromStr for Network {
330 type Err = InvalidNetworkError;
331
332 fn from_str(string: &str) -> Result<Self, Self::Err> {
333 match string.to_lowercase().as_str() {
334 "mainnet" => Ok(Network::Mainnet),
335 "testnet" => Ok(Network::new_default_testnet()),
336 _ => Err(InvalidNetworkError(string.to_owned())),
337 }
338 }
339}
340
341#[derive(Clone, Debug, Error)]
342#[error("Invalid network: {0}")]
343pub struct InvalidNetworkError(String);
344
345impl zcash_protocol::consensus::Parameters for Network {
346 fn network_type(&self) -> zcash_protocol::consensus::NetworkType {
347 self.kind().into()
348 }
349
350 fn activation_height(
351 &self,
352 nu: zcash_protocol::consensus::NetworkUpgrade,
353 ) -> Option<zcash_protocol::consensus::BlockHeight> {
354 NetworkUpgrade::from(nu)
355 .activation_height(self)
356 .map(|Height(h)| zcash_protocol::consensus::BlockHeight::from_u32(h))
357 }
358}