1use crate::{NetworkParameters, ProtocolVersion, Result};
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct NetworkConstants {
13 pub magic_bytes: [u8; 4],
15 pub default_port: u16,
17 pub genesis_hash: [u8; 32],
19 pub max_target: u32,
21 pub halving_interval: u64,
23 pub network_name: String,
25 pub is_testnet: bool,
27 pub dns_seeds: Vec<String>,
29 pub checkpoints: Vec<Checkpoint>,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35pub struct Checkpoint {
36 pub height: u64,
38 pub hash: [u8; 32],
40 pub timestamp: u64,
42}
43
44impl NetworkConstants {
45 pub fn for_version(version: ProtocolVersion) -> Result<Self> {
47 match version {
48 ProtocolVersion::BitcoinV1 => Self::mainnet(),
49 ProtocolVersion::Testnet3 => Self::testnet(),
50 ProtocolVersion::Regtest => Self::regtest(),
51 }
52 }
53
54 pub fn mainnet() -> Result<Self> {
56 Ok(Self {
57 magic_bytes: [0xf9, 0xbe, 0xb4, 0xd9], default_port: 8333,
59 genesis_hash: [
60 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63,
61 0xf7, 0x4f, 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, 0x68, 0xd6, 0x19, 0x00,
62 0x00, 0x00, 0x00, 0x00,
63 ],
64 max_target: 0x1d00ffff,
65 halving_interval: 210000,
66 network_name: "mainnet".to_string(),
67 is_testnet: false,
68 dns_seeds: vec![
69 "seed.bitcoin.sipa.be".to_string(),
70 "dnsseed.bluematt.me".to_string(),
71 "dnsseed.bitcoin.dashjr.org".to_string(),
72 "seed.bitcoinstats.com".to_string(),
73 "seed.bitcoin.jonasschnelli.ch".to_string(),
74 "seed.btc.petertodd.org".to_string(),
75 ],
76 checkpoints: Self::mainnet_checkpoints(),
77 })
78 }
79
80 pub fn testnet() -> Result<Self> {
82 Ok(Self {
83 magic_bytes: [0x0b, 0x11, 0x09, 0x07], default_port: 18333,
85 genesis_hash: [
86 0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95, 0x71, 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce,
87 0xc3, 0xae, 0xba, 0x79, 0x97, 0x20, 0x84, 0xe9, 0x0e, 0xad, 0x01, 0xea, 0x33, 0x09,
88 0x00, 0x00, 0x00, 0x00,
89 ],
90 max_target: 0x1d00ffff,
91 halving_interval: 210000,
92 network_name: "testnet".to_string(),
93 is_testnet: true,
94 dns_seeds: vec![
95 "testnet-seed.bitcoin.jonasschnelli.ch".to_string(),
96 "seed.tbtc.petertodd.org".to_string(),
97 "seed.testnet.bitcoin.sprovoost.nl".to_string(),
98 "testnet-seed.bluematt.me".to_string(),
99 ],
100 checkpoints: Self::testnet_checkpoints(),
101 })
102 }
103
104 pub fn regtest() -> Result<Self> {
106 Ok(Self {
107 magic_bytes: [0xfa, 0xbf, 0xb5, 0xda], default_port: 18444,
109 genesis_hash: [
110 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb,
111 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c,
112 0xf1, 0x88, 0x91, 0x0f,
113 ],
114 max_target: 0x207fffff, halving_interval: 150, network_name: "regtest".to_string(),
117 is_testnet: true,
118 dns_seeds: vec![], checkpoints: vec![], })
121 }
122
123 fn mainnet_checkpoints() -> Vec<Checkpoint> {
125 vec![
126 Checkpoint {
127 height: 11111,
128 hash: [
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 ],
133 timestamp: 1231006505,
134 },
135 ]
137 }
138
139 fn testnet_checkpoints() -> Vec<Checkpoint> {
141 vec![
142 Checkpoint {
143 height: 11111,
144 hash: [
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 ],
149 timestamp: 1296688602,
150 },
151 ]
153 }
154}
155
156impl NetworkParameters {
157 pub fn from_constants(constants: &NetworkConstants) -> Result<Self> {
159 Ok(NetworkParameters {
160 magic_bytes: constants.magic_bytes,
161 default_port: constants.default_port,
162 genesis_block: crate::genesis::mainnet_genesis(),
163 max_target: constants.max_target,
164 halving_interval: constants.halving_interval,
165 network_name: constants.network_name.clone(),
166 is_testnet: constants.is_testnet,
167 })
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 #[test]
176 fn test_network_constants() {
177 let mainnet = NetworkConstants::mainnet().unwrap();
178 assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
179 assert_eq!(mainnet.default_port, 8333);
180 assert!(!mainnet.is_testnet);
181 assert!(!mainnet.dns_seeds.is_empty());
182
183 let testnet = NetworkConstants::testnet().unwrap();
184 assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
185 assert_eq!(testnet.default_port, 18333);
186 assert!(testnet.is_testnet);
187
188 let regtest = NetworkConstants::regtest().unwrap();
189 assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
190 assert_eq!(regtest.default_port, 18444);
191 assert!(regtest.is_testnet);
192 assert!(regtest.dns_seeds.is_empty());
193 }
194
195 #[test]
196 fn test_network_parameters_from_constants() {
197 let constants = NetworkConstants::mainnet().unwrap();
198 let params = NetworkParameters::from_constants(&constants).unwrap();
199
200 assert_eq!(params.magic_bytes, constants.magic_bytes);
201 assert_eq!(params.default_port, constants.default_port);
202 assert_eq!(params.network_name, constants.network_name);
203 assert_eq!(params.is_testnet, constants.is_testnet);
204 }
205
206 #[test]
207 fn test_network_constants_for_version() {
208 let mainnet = NetworkConstants::for_version(ProtocolVersion::BitcoinV1).unwrap();
209 assert_eq!(mainnet.network_name, "mainnet");
210 assert!(!mainnet.is_testnet);
211
212 let testnet = NetworkConstants::for_version(ProtocolVersion::Testnet3).unwrap();
213 assert_eq!(testnet.network_name, "testnet");
214 assert!(testnet.is_testnet);
215
216 let regtest = NetworkConstants::for_version(ProtocolVersion::Regtest).unwrap();
217 assert_eq!(regtest.network_name, "regtest");
218 assert!(regtest.is_testnet);
219 }
220
221 #[test]
222 fn test_genesis_hashes() {
223 let mainnet = NetworkConstants::mainnet().unwrap();
224 let testnet = NetworkConstants::testnet().unwrap();
225 let regtest = NetworkConstants::regtest().unwrap();
226
227 assert_ne!(mainnet.genesis_hash, testnet.genesis_hash);
229 assert_ne!(testnet.genesis_hash, regtest.genesis_hash);
230 assert_ne!(mainnet.genesis_hash, regtest.genesis_hash);
231
232 assert_ne!(mainnet.genesis_hash, [0u8; 32]);
234 assert_ne!(testnet.genesis_hash, [0u8; 32]);
235 assert_ne!(regtest.genesis_hash, [0u8; 32]);
236 }
237
238 #[test]
239 fn test_dns_seeds() {
240 let mainnet = NetworkConstants::mainnet().unwrap();
241 let testnet = NetworkConstants::testnet().unwrap();
242 let regtest = NetworkConstants::regtest().unwrap();
243
244 assert!(!mainnet.dns_seeds.is_empty());
246 assert!(mainnet
247 .dns_seeds
248 .iter()
249 .any(|seed| seed.contains("bitcoin")));
250
251 assert!(!testnet.dns_seeds.is_empty());
253 assert!(testnet
254 .dns_seeds
255 .iter()
256 .any(|seed| seed.contains("testnet")));
257
258 assert!(regtest.dns_seeds.is_empty());
260 }
261
262 #[test]
263 fn test_checkpoints() {
264 let mainnet = NetworkConstants::mainnet().unwrap();
265 let testnet = NetworkConstants::testnet().unwrap();
266 let regtest = NetworkConstants::regtest().unwrap();
267
268 assert!(!mainnet.checkpoints.is_empty());
270
271 assert!(!testnet.checkpoints.is_empty());
273
274 assert!(regtest.checkpoints.is_empty());
276
277 for checkpoints in [&mainnet.checkpoints, &testnet.checkpoints] {
279 for i in 1..checkpoints.len() {
280 assert!(checkpoints[i].height > checkpoints[i - 1].height);
281 }
282 }
283 }
284
285 #[test]
286 fn test_max_targets() {
287 let mainnet = NetworkConstants::mainnet().unwrap();
288 let testnet = NetworkConstants::testnet().unwrap();
289 let regtest = NetworkConstants::regtest().unwrap();
290
291 assert_eq!(mainnet.max_target, 0x1d00ffff);
293 assert_eq!(testnet.max_target, 0x1d00ffff);
294
295 assert_eq!(regtest.max_target, 0x207fffff);
297 assert!(regtest.max_target > mainnet.max_target);
298 }
299
300 #[test]
301 fn test_halving_intervals() {
302 let mainnet = NetworkConstants::mainnet().unwrap();
303 let testnet = NetworkConstants::testnet().unwrap();
304 let regtest = NetworkConstants::regtest().unwrap();
305
306 assert_eq!(mainnet.halving_interval, 210000);
308 assert_eq!(testnet.halving_interval, 210000);
309
310 assert_eq!(regtest.halving_interval, 150);
312 assert!(regtest.halving_interval < mainnet.halving_interval);
313 }
314
315 #[test]
316 fn test_network_constants_serialization() {
317 let mainnet = NetworkConstants::mainnet().unwrap();
318 let testnet = NetworkConstants::testnet().unwrap();
319 let regtest = NetworkConstants::regtest().unwrap();
320
321 for constants in [mainnet, testnet, regtest] {
323 let json = serde_json::to_string(&constants).unwrap();
324 let deserialized: NetworkConstants = serde_json::from_str(&json).unwrap();
325
326 assert_eq!(constants.magic_bytes, deserialized.magic_bytes);
327 assert_eq!(constants.default_port, deserialized.default_port);
328 assert_eq!(constants.genesis_hash, deserialized.genesis_hash);
329 assert_eq!(constants.max_target, deserialized.max_target);
330 assert_eq!(constants.halving_interval, deserialized.halving_interval);
331 assert_eq!(constants.network_name, deserialized.network_name);
332 assert_eq!(constants.is_testnet, deserialized.is_testnet);
333 assert_eq!(constants.dns_seeds, deserialized.dns_seeds);
334 assert_eq!(constants.checkpoints, deserialized.checkpoints);
335 }
336 }
337
338 #[test]
339 fn test_checkpoint_serialization() {
340 let checkpoint = Checkpoint {
341 height: 1000,
342 hash: [
343 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02,
344 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
345 0x01, 0x02, 0x03, 0x04,
346 ],
347 timestamp: 1234567890,
348 };
349
350 let json = serde_json::to_string(&checkpoint).unwrap();
351 let deserialized: Checkpoint = serde_json::from_str(&json).unwrap();
352
353 assert_eq!(checkpoint.height, deserialized.height);
354 assert_eq!(checkpoint.hash, deserialized.hash);
355 assert_eq!(checkpoint.timestamp, deserialized.timestamp);
356 }
357
358 #[test]
359 fn test_network_constants_equality() {
360 let mainnet1 = NetworkConstants::mainnet().unwrap();
361 let mainnet2 = NetworkConstants::mainnet().unwrap();
362 let testnet = NetworkConstants::testnet().unwrap();
363
364 assert_eq!(mainnet1, mainnet2);
365 assert_ne!(mainnet1, testnet);
366 }
367
368 #[test]
369 fn test_checkpoint_equality() {
370 let checkpoint1 = Checkpoint {
371 height: 1000,
372 hash: [0x01; 32],
373 timestamp: 1234567890,
374 };
375
376 let checkpoint2 = Checkpoint {
377 height: 1000,
378 hash: [0x01; 32],
379 timestamp: 1234567890,
380 };
381
382 let checkpoint3 = Checkpoint {
383 height: 1001,
384 hash: [0x01; 32],
385 timestamp: 1234567890,
386 };
387
388 assert_eq!(checkpoint1, checkpoint2);
389 assert_ne!(checkpoint1, checkpoint3);
390 }
391
392 #[test]
393 fn test_network_parameters_consistency() {
394 let mainnet_constants = NetworkConstants::mainnet().unwrap();
395 let mainnet_params = NetworkParameters::from_constants(&mainnet_constants).unwrap();
396
397 assert_eq!(mainnet_params.magic_bytes, mainnet_constants.magic_bytes);
398 assert_eq!(mainnet_params.default_port, mainnet_constants.default_port);
399 assert_eq!(mainnet_params.max_target, mainnet_constants.max_target);
400 assert_eq!(
401 mainnet_params.halving_interval,
402 mainnet_constants.halving_interval
403 );
404 assert_eq!(mainnet_params.network_name, mainnet_constants.network_name);
405 assert_eq!(mainnet_params.is_testnet, mainnet_constants.is_testnet);
406 }
407
408 #[test]
409 fn test_all_networks_have_unique_magic_bytes() {
410 let mainnet = NetworkConstants::mainnet().unwrap();
411 let testnet = NetworkConstants::testnet().unwrap();
412 let regtest = NetworkConstants::regtest().unwrap();
413
414 assert_ne!(mainnet.magic_bytes, testnet.magic_bytes);
415 assert_ne!(testnet.magic_bytes, regtest.magic_bytes);
416 assert_ne!(mainnet.magic_bytes, regtest.magic_bytes);
417 }
418
419 #[test]
420 fn test_all_networks_have_unique_ports() {
421 let mainnet = NetworkConstants::mainnet().unwrap();
422 let testnet = NetworkConstants::testnet().unwrap();
423 let regtest = NetworkConstants::regtest().unwrap();
424
425 assert_ne!(mainnet.default_port, testnet.default_port);
426 assert_ne!(testnet.default_port, regtest.default_port);
427 assert_ne!(mainnet.default_port, regtest.default_port);
428 }
429
430 #[test]
431 fn test_network_names() {
432 let mainnet = NetworkConstants::mainnet().unwrap();
433 let testnet = NetworkConstants::testnet().unwrap();
434 let regtest = NetworkConstants::regtest().unwrap();
435
436 assert_eq!(mainnet.network_name, "mainnet");
437 assert_eq!(testnet.network_name, "testnet");
438 assert_eq!(regtest.network_name, "regtest");
439 }
440
441 #[test]
442 fn test_testnet_flags() {
443 let mainnet = NetworkConstants::mainnet().unwrap();
444 let testnet = NetworkConstants::testnet().unwrap();
445 let regtest = NetworkConstants::regtest().unwrap();
446
447 assert!(!mainnet.is_testnet);
448 assert!(testnet.is_testnet);
449 assert!(regtest.is_testnet);
450 }
451}