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 ProtocolVersion::Signet => Self::signet(),
52 }
53 }
54
55 pub fn mainnet() -> Result<Self> {
57 Ok(Self {
58 magic_bytes: [0xf9, 0xbe, 0xb4, 0xd9], default_port: 8333,
60 genesis_hash: [
61 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63,
62 0xf7, 0x4f, 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, 0x68, 0xd6, 0x19, 0x00,
63 0x00, 0x00, 0x00, 0x00,
64 ],
65 max_target: 0x1d00ffff,
66 halving_interval: 210000,
67 network_name: "mainnet".to_string(),
68 is_testnet: false,
69 dns_seeds: vec![
70 "seed.bitcoin.sipa.be".to_string(),
71 "dnsseed.bluematt.me".to_string(),
72 "dnsseed.bitcoin.dashjr.org".to_string(),
73 "seed.bitcoinstats.com".to_string(),
74 "seed.bitcoin.jonasschnelli.ch".to_string(),
75 "seed.btc.petertodd.org".to_string(),
76 ],
77 checkpoints: Self::mainnet_checkpoints(),
78 })
79 }
80
81 pub fn testnet() -> Result<Self> {
83 Ok(Self {
84 magic_bytes: [0x0b, 0x11, 0x09, 0x07], default_port: 18333,
86 genesis_hash: [
87 0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95, 0x71, 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce,
88 0xc3, 0xae, 0xba, 0x79, 0x97, 0x20, 0x84, 0xe9, 0x0e, 0xad, 0x01, 0xea, 0x33, 0x09,
89 0x00, 0x00, 0x00, 0x00,
90 ],
91 max_target: 0x1d00ffff,
92 halving_interval: 210000,
93 network_name: "testnet".to_string(),
94 is_testnet: true,
95 dns_seeds: vec![
96 "testnet-seed.bitcoin.jonasschnelli.ch".to_string(),
97 "seed.tbtc.petertodd.org".to_string(),
98 "seed.testnet.bitcoin.sprovoost.nl".to_string(),
99 "testnet-seed.bluematt.me".to_string(),
100 ],
101 checkpoints: Self::testnet_checkpoints(),
102 })
103 }
104
105 pub fn regtest() -> Result<Self> {
107 Ok(Self {
108 magic_bytes: [0xfa, 0xbf, 0xb5, 0xda], default_port: 18444,
110 genesis_hash: [
111 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb,
112 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c,
113 0xf1, 0x88, 0x91, 0x0f,
114 ],
115 max_target: 0x207fffff, halving_interval: 150, network_name: "regtest".to_string(),
118 is_testnet: true,
119 dns_seeds: vec![], checkpoints: vec![], })
122 }
123
124 pub fn signet() -> Result<Self> {
126 Ok(Self {
127 magic_bytes: [0x0f, 0x1b, 0xf2, 0xe1],
128 default_port: 38333,
129 genesis_hash: [
130 0xf6, 0x1e, 0xee, 0x3b, 0x63, 0xa3, 0x80, 0xa4, 0x77, 0xa0, 0x63, 0xaf, 0x32, 0xb2,
131 0xbb, 0xc9, 0x7c, 0x9f, 0xf9, 0xf0, 0x1f, 0x2c, 0x42, 0x25, 0xe9, 0x73, 0x98, 0x81,
132 0x08, 0x00, 0x00, 0x00,
133 ],
134 max_target: 0x1e0377ae,
135 halving_interval: 210_000,
136 network_name: "signet".to_string(),
137 is_testnet: true,
138 dns_seeds: vec![
139 "seed.signet.bitcoin.sprovoost.nl".to_string(),
140 "seed.signet.achownodes.xyz".to_string(),
141 ],
142 checkpoints: vec![],
143 })
144 }
145
146 fn mainnet_checkpoints() -> Vec<Checkpoint> {
148 vec![
149 Checkpoint {
150 height: 11111,
151 hash: [
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 ],
156 timestamp: 1231006505,
157 },
158 ]
160 }
161
162 fn testnet_checkpoints() -> Vec<Checkpoint> {
164 vec![
165 Checkpoint {
166 height: 11111,
167 hash: [
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 ],
172 timestamp: 1296688602,
173 },
174 ]
176 }
177}
178
179impl NetworkParameters {
180 pub fn from_constants(constants: &NetworkConstants) -> Result<Self> {
182 let genesis_block = match constants.network_name.as_str() {
183 "testnet" => crate::genesis::testnet_genesis(),
184 "regtest" => crate::genesis::regtest_genesis(),
185 "signet" => crate::genesis::signet_genesis(),
186 _ => crate::genesis::mainnet_genesis(),
187 };
188 Ok(NetworkParameters {
189 magic_bytes: constants.magic_bytes,
190 default_port: constants.default_port,
191 genesis_block,
192 max_target: constants.max_target,
193 halving_interval: constants.halving_interval,
194 network_name: constants.network_name.clone(),
195 is_testnet: constants.is_testnet,
196 signet_challenge: None,
197 })
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_network_constants() {
207 let mainnet = NetworkConstants::mainnet().unwrap();
208 assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
209 assert_eq!(mainnet.default_port, 8333);
210 assert!(!mainnet.is_testnet);
211 assert!(!mainnet.dns_seeds.is_empty());
212
213 let testnet = NetworkConstants::testnet().unwrap();
214 assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
215 assert_eq!(testnet.default_port, 18333);
216 assert!(testnet.is_testnet);
217
218 let regtest = NetworkConstants::regtest().unwrap();
219 assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
220 assert_eq!(regtest.default_port, 18444);
221 assert!(regtest.is_testnet);
222 assert!(regtest.dns_seeds.is_empty());
223
224 let signet = NetworkConstants::signet().unwrap();
225 assert_eq!(signet.magic_bytes, [0x0f, 0x1b, 0xf2, 0xe1]);
226 assert_eq!(signet.default_port, 38333);
227 assert!(signet.is_testnet);
228 assert!(!signet.dns_seeds.is_empty());
229 }
230
231 #[test]
232 fn test_network_parameters_from_constants() {
233 let constants = NetworkConstants::mainnet().unwrap();
234 let params = NetworkParameters::from_constants(&constants).unwrap();
235
236 assert_eq!(params.magic_bytes, constants.magic_bytes);
237 assert_eq!(params.default_port, constants.default_port);
238 assert_eq!(params.network_name, constants.network_name);
239 assert_eq!(params.is_testnet, constants.is_testnet);
240 }
241
242 #[test]
243 fn test_network_constants_for_version() {
244 let mainnet = NetworkConstants::for_version(ProtocolVersion::BitcoinV1).unwrap();
245 assert_eq!(mainnet.network_name, "mainnet");
246 assert!(!mainnet.is_testnet);
247
248 let testnet = NetworkConstants::for_version(ProtocolVersion::Testnet3).unwrap();
249 assert_eq!(testnet.network_name, "testnet");
250 assert!(testnet.is_testnet);
251
252 let regtest = NetworkConstants::for_version(ProtocolVersion::Regtest).unwrap();
253 assert_eq!(regtest.network_name, "regtest");
254 assert!(regtest.is_testnet);
255
256 let signet = NetworkConstants::for_version(ProtocolVersion::Signet).unwrap();
257 assert_eq!(signet.network_name, "signet");
258 assert!(signet.is_testnet);
259 }
260
261 #[test]
262 fn test_genesis_hashes() {
263 let mainnet = NetworkConstants::mainnet().unwrap();
264 let testnet = NetworkConstants::testnet().unwrap();
265 let regtest = NetworkConstants::regtest().unwrap();
266
267 assert_ne!(mainnet.genesis_hash, testnet.genesis_hash);
269 assert_ne!(testnet.genesis_hash, regtest.genesis_hash);
270 assert_ne!(mainnet.genesis_hash, regtest.genesis_hash);
271
272 let signet = NetworkConstants::signet().unwrap();
273 assert_ne!(signet.genesis_hash, mainnet.genesis_hash);
274 assert_ne!(signet.genesis_hash, testnet.genesis_hash);
275 assert_ne!(signet.genesis_hash, regtest.genesis_hash);
276
277 assert_ne!(mainnet.genesis_hash, [0u8; 32]);
279 assert_ne!(testnet.genesis_hash, [0u8; 32]);
280 assert_ne!(regtest.genesis_hash, [0u8; 32]);
281 }
282
283 #[test]
284 fn test_dns_seeds() {
285 let mainnet = NetworkConstants::mainnet().unwrap();
286 let testnet = NetworkConstants::testnet().unwrap();
287 let regtest = NetworkConstants::regtest().unwrap();
288
289 assert!(!mainnet.dns_seeds.is_empty());
291 assert!(
292 mainnet
293 .dns_seeds
294 .iter()
295 .any(|seed| seed.contains("bitcoin"))
296 );
297
298 assert!(!testnet.dns_seeds.is_empty());
300 assert!(
301 testnet
302 .dns_seeds
303 .iter()
304 .any(|seed| seed.contains("testnet"))
305 );
306
307 assert!(regtest.dns_seeds.is_empty());
309 }
310
311 #[test]
312 fn test_checkpoints() {
313 let mainnet = NetworkConstants::mainnet().unwrap();
314 let testnet = NetworkConstants::testnet().unwrap();
315 let regtest = NetworkConstants::regtest().unwrap();
316
317 assert!(!mainnet.checkpoints.is_empty());
319
320 assert!(!testnet.checkpoints.is_empty());
322
323 assert!(regtest.checkpoints.is_empty());
325
326 for checkpoints in [&mainnet.checkpoints, &testnet.checkpoints] {
328 for i in 1..checkpoints.len() {
329 assert!(checkpoints[i].height > checkpoints[i - 1].height);
330 }
331 }
332 }
333
334 #[test]
335 fn test_max_targets() {
336 let mainnet = NetworkConstants::mainnet().unwrap();
337 let testnet = NetworkConstants::testnet().unwrap();
338 let regtest = NetworkConstants::regtest().unwrap();
339
340 assert_eq!(mainnet.max_target, 0x1d00ffff);
342 assert_eq!(testnet.max_target, 0x1d00ffff);
343
344 assert_eq!(regtest.max_target, 0x207fffff);
346 assert!(regtest.max_target > mainnet.max_target);
347 }
348
349 #[test]
350 fn test_halving_intervals() {
351 let mainnet = NetworkConstants::mainnet().unwrap();
352 let testnet = NetworkConstants::testnet().unwrap();
353 let regtest = NetworkConstants::regtest().unwrap();
354
355 assert_eq!(mainnet.halving_interval, 210000);
357 assert_eq!(testnet.halving_interval, 210000);
358
359 assert_eq!(regtest.halving_interval, 150);
361 assert!(regtest.halving_interval < mainnet.halving_interval);
362 }
363
364 #[test]
365 fn test_network_constants_serialization() {
366 let mainnet = NetworkConstants::mainnet().unwrap();
367 let testnet = NetworkConstants::testnet().unwrap();
368 let regtest = NetworkConstants::regtest().unwrap();
369
370 for constants in [mainnet, testnet, regtest] {
372 let json = serde_json::to_string(&constants).unwrap();
373 let deserialized: NetworkConstants = serde_json::from_str(&json).unwrap();
374
375 assert_eq!(constants.magic_bytes, deserialized.magic_bytes);
376 assert_eq!(constants.default_port, deserialized.default_port);
377 assert_eq!(constants.genesis_hash, deserialized.genesis_hash);
378 assert_eq!(constants.max_target, deserialized.max_target);
379 assert_eq!(constants.halving_interval, deserialized.halving_interval);
380 assert_eq!(constants.network_name, deserialized.network_name);
381 assert_eq!(constants.is_testnet, deserialized.is_testnet);
382 assert_eq!(constants.dns_seeds, deserialized.dns_seeds);
383 assert_eq!(constants.checkpoints, deserialized.checkpoints);
384 }
385 }
386
387 #[test]
388 fn test_checkpoint_serialization() {
389 let checkpoint = Checkpoint {
390 height: 1000,
391 hash: [
392 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02,
393 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
394 0x01, 0x02, 0x03, 0x04,
395 ],
396 timestamp: 1234567890,
397 };
398
399 let json = serde_json::to_string(&checkpoint).unwrap();
400 let deserialized: Checkpoint = serde_json::from_str(&json).unwrap();
401
402 assert_eq!(checkpoint.height, deserialized.height);
403 assert_eq!(checkpoint.hash, deserialized.hash);
404 assert_eq!(checkpoint.timestamp, deserialized.timestamp);
405 }
406
407 #[test]
408 fn test_network_constants_equality() {
409 let mainnet1 = NetworkConstants::mainnet().unwrap();
410 let mainnet2 = NetworkConstants::mainnet().unwrap();
411 let testnet = NetworkConstants::testnet().unwrap();
412
413 assert_eq!(mainnet1, mainnet2);
414 assert_ne!(mainnet1, testnet);
415 }
416
417 #[test]
418 fn test_checkpoint_equality() {
419 let checkpoint1 = Checkpoint {
420 height: 1000,
421 hash: [0x01; 32],
422 timestamp: 1234567890,
423 };
424
425 let checkpoint2 = Checkpoint {
426 height: 1000,
427 hash: [0x01; 32],
428 timestamp: 1234567890,
429 };
430
431 let checkpoint3 = Checkpoint {
432 height: 1001,
433 hash: [0x01; 32],
434 timestamp: 1234567890,
435 };
436
437 assert_eq!(checkpoint1, checkpoint2);
438 assert_ne!(checkpoint1, checkpoint3);
439 }
440
441 #[test]
442 fn test_network_parameters_consistency() {
443 let mainnet_constants = NetworkConstants::mainnet().unwrap();
444 let mainnet_params = NetworkParameters::from_constants(&mainnet_constants).unwrap();
445
446 assert_eq!(mainnet_params.magic_bytes, mainnet_constants.magic_bytes);
447 assert_eq!(mainnet_params.default_port, mainnet_constants.default_port);
448 assert_eq!(mainnet_params.max_target, mainnet_constants.max_target);
449 assert_eq!(
450 mainnet_params.halving_interval,
451 mainnet_constants.halving_interval
452 );
453 assert_eq!(mainnet_params.network_name, mainnet_constants.network_name);
454 assert_eq!(mainnet_params.is_testnet, mainnet_constants.is_testnet);
455 }
456
457 #[test]
458 fn test_all_networks_have_unique_magic_bytes() {
459 let mainnet = NetworkConstants::mainnet().unwrap();
460 let testnet = NetworkConstants::testnet().unwrap();
461 let regtest = NetworkConstants::regtest().unwrap();
462
463 assert_ne!(mainnet.magic_bytes, testnet.magic_bytes);
464 assert_ne!(testnet.magic_bytes, regtest.magic_bytes);
465 assert_ne!(mainnet.magic_bytes, regtest.magic_bytes);
466 }
467
468 #[test]
469 fn test_all_networks_have_unique_ports() {
470 let mainnet = NetworkConstants::mainnet().unwrap();
471 let testnet = NetworkConstants::testnet().unwrap();
472 let regtest = NetworkConstants::regtest().unwrap();
473
474 assert_ne!(mainnet.default_port, testnet.default_port);
475 assert_ne!(testnet.default_port, regtest.default_port);
476 assert_ne!(mainnet.default_port, regtest.default_port);
477 }
478
479 #[test]
480 fn test_network_names() {
481 let mainnet = NetworkConstants::mainnet().unwrap();
482 let testnet = NetworkConstants::testnet().unwrap();
483 let regtest = NetworkConstants::regtest().unwrap();
484
485 assert_eq!(mainnet.network_name, "mainnet");
486 assert_eq!(testnet.network_name, "testnet");
487 assert_eq!(regtest.network_name, "regtest");
488 }
489
490 #[test]
491 fn test_testnet_flags() {
492 let mainnet = NetworkConstants::mainnet().unwrap();
493 let testnet = NetworkConstants::testnet().unwrap();
494 let regtest = NetworkConstants::regtest().unwrap();
495
496 assert!(!mainnet.is_testnet);
497 assert!(testnet.is_testnet);
498 assert!(regtest.is_testnet);
499 }
500}