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!(
247 mainnet
248 .dns_seeds
249 .iter()
250 .any(|seed| seed.contains("bitcoin"))
251 );
252
253 assert!(!testnet.dns_seeds.is_empty());
255 assert!(
256 testnet
257 .dns_seeds
258 .iter()
259 .any(|seed| seed.contains("testnet"))
260 );
261
262 assert!(regtest.dns_seeds.is_empty());
264 }
265
266 #[test]
267 fn test_checkpoints() {
268 let mainnet = NetworkConstants::mainnet().unwrap();
269 let testnet = NetworkConstants::testnet().unwrap();
270 let regtest = NetworkConstants::regtest().unwrap();
271
272 assert!(!mainnet.checkpoints.is_empty());
274
275 assert!(!testnet.checkpoints.is_empty());
277
278 assert!(regtest.checkpoints.is_empty());
280
281 for checkpoints in [&mainnet.checkpoints, &testnet.checkpoints] {
283 for i in 1..checkpoints.len() {
284 assert!(checkpoints[i].height > checkpoints[i - 1].height);
285 }
286 }
287 }
288
289 #[test]
290 fn test_max_targets() {
291 let mainnet = NetworkConstants::mainnet().unwrap();
292 let testnet = NetworkConstants::testnet().unwrap();
293 let regtest = NetworkConstants::regtest().unwrap();
294
295 assert_eq!(mainnet.max_target, 0x1d00ffff);
297 assert_eq!(testnet.max_target, 0x1d00ffff);
298
299 assert_eq!(regtest.max_target, 0x207fffff);
301 assert!(regtest.max_target > mainnet.max_target);
302 }
303
304 #[test]
305 fn test_halving_intervals() {
306 let mainnet = NetworkConstants::mainnet().unwrap();
307 let testnet = NetworkConstants::testnet().unwrap();
308 let regtest = NetworkConstants::regtest().unwrap();
309
310 assert_eq!(mainnet.halving_interval, 210000);
312 assert_eq!(testnet.halving_interval, 210000);
313
314 assert_eq!(regtest.halving_interval, 150);
316 assert!(regtest.halving_interval < mainnet.halving_interval);
317 }
318
319 #[test]
320 fn test_network_constants_serialization() {
321 let mainnet = NetworkConstants::mainnet().unwrap();
322 let testnet = NetworkConstants::testnet().unwrap();
323 let regtest = NetworkConstants::regtest().unwrap();
324
325 for constants in [mainnet, testnet, regtest] {
327 let json = serde_json::to_string(&constants).unwrap();
328 let deserialized: NetworkConstants = serde_json::from_str(&json).unwrap();
329
330 assert_eq!(constants.magic_bytes, deserialized.magic_bytes);
331 assert_eq!(constants.default_port, deserialized.default_port);
332 assert_eq!(constants.genesis_hash, deserialized.genesis_hash);
333 assert_eq!(constants.max_target, deserialized.max_target);
334 assert_eq!(constants.halving_interval, deserialized.halving_interval);
335 assert_eq!(constants.network_name, deserialized.network_name);
336 assert_eq!(constants.is_testnet, deserialized.is_testnet);
337 assert_eq!(constants.dns_seeds, deserialized.dns_seeds);
338 assert_eq!(constants.checkpoints, deserialized.checkpoints);
339 }
340 }
341
342 #[test]
343 fn test_checkpoint_serialization() {
344 let checkpoint = Checkpoint {
345 height: 1000,
346 hash: [
347 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02,
348 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
349 0x01, 0x02, 0x03, 0x04,
350 ],
351 timestamp: 1234567890,
352 };
353
354 let json = serde_json::to_string(&checkpoint).unwrap();
355 let deserialized: Checkpoint = serde_json::from_str(&json).unwrap();
356
357 assert_eq!(checkpoint.height, deserialized.height);
358 assert_eq!(checkpoint.hash, deserialized.hash);
359 assert_eq!(checkpoint.timestamp, deserialized.timestamp);
360 }
361
362 #[test]
363 fn test_network_constants_equality() {
364 let mainnet1 = NetworkConstants::mainnet().unwrap();
365 let mainnet2 = NetworkConstants::mainnet().unwrap();
366 let testnet = NetworkConstants::testnet().unwrap();
367
368 assert_eq!(mainnet1, mainnet2);
369 assert_ne!(mainnet1, testnet);
370 }
371
372 #[test]
373 fn test_checkpoint_equality() {
374 let checkpoint1 = Checkpoint {
375 height: 1000,
376 hash: [0x01; 32],
377 timestamp: 1234567890,
378 };
379
380 let checkpoint2 = Checkpoint {
381 height: 1000,
382 hash: [0x01; 32],
383 timestamp: 1234567890,
384 };
385
386 let checkpoint3 = Checkpoint {
387 height: 1001,
388 hash: [0x01; 32],
389 timestamp: 1234567890,
390 };
391
392 assert_eq!(checkpoint1, checkpoint2);
393 assert_ne!(checkpoint1, checkpoint3);
394 }
395
396 #[test]
397 fn test_network_parameters_consistency() {
398 let mainnet_constants = NetworkConstants::mainnet().unwrap();
399 let mainnet_params = NetworkParameters::from_constants(&mainnet_constants).unwrap();
400
401 assert_eq!(mainnet_params.magic_bytes, mainnet_constants.magic_bytes);
402 assert_eq!(mainnet_params.default_port, mainnet_constants.default_port);
403 assert_eq!(mainnet_params.max_target, mainnet_constants.max_target);
404 assert_eq!(
405 mainnet_params.halving_interval,
406 mainnet_constants.halving_interval
407 );
408 assert_eq!(mainnet_params.network_name, mainnet_constants.network_name);
409 assert_eq!(mainnet_params.is_testnet, mainnet_constants.is_testnet);
410 }
411
412 #[test]
413 fn test_all_networks_have_unique_magic_bytes() {
414 let mainnet = NetworkConstants::mainnet().unwrap();
415 let testnet = NetworkConstants::testnet().unwrap();
416 let regtest = NetworkConstants::regtest().unwrap();
417
418 assert_ne!(mainnet.magic_bytes, testnet.magic_bytes);
419 assert_ne!(testnet.magic_bytes, regtest.magic_bytes);
420 assert_ne!(mainnet.magic_bytes, regtest.magic_bytes);
421 }
422
423 #[test]
424 fn test_all_networks_have_unique_ports() {
425 let mainnet = NetworkConstants::mainnet().unwrap();
426 let testnet = NetworkConstants::testnet().unwrap();
427 let regtest = NetworkConstants::regtest().unwrap();
428
429 assert_ne!(mainnet.default_port, testnet.default_port);
430 assert_ne!(testnet.default_port, regtest.default_port);
431 assert_ne!(mainnet.default_port, regtest.default_port);
432 }
433
434 #[test]
435 fn test_network_names() {
436 let mainnet = NetworkConstants::mainnet().unwrap();
437 let testnet = NetworkConstants::testnet().unwrap();
438 let regtest = NetworkConstants::regtest().unwrap();
439
440 assert_eq!(mainnet.network_name, "mainnet");
441 assert_eq!(testnet.network_name, "testnet");
442 assert_eq!(regtest.network_name, "regtest");
443 }
444
445 #[test]
446 fn test_testnet_flags() {
447 let mainnet = NetworkConstants::mainnet().unwrap();
448 let testnet = NetworkConstants::testnet().unwrap();
449 let regtest = NetworkConstants::regtest().unwrap();
450
451 assert!(!mainnet.is_testnet);
452 assert!(testnet.is_testnet);
453 assert!(regtest.is_testnet);
454 }
455}