bitcoin/
network.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Bitcoin network.
4//!
5//! The term "network" is overloaded, here [`Network`] refers to the specific
6//! Bitcoin network we are operating on e.g., signet, regtest. The terms
7//! "network" and "chain" are often used interchangeably for this concept.
8//!
9//! # Example: encoding a network's magic bytes
10//!
11//! ```rust
12//! use bitcoin::Network;
13//! use bitcoin::consensus::encode::serialize;
14//!
15//! let network = Network::Bitcoin;
16//! let bytes = serialize(&network.magic());
17//!
18//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]);
19//! ```
20
21use core::fmt;
22use core::fmt::Display;
23use core::str::FromStr;
24
25use internals::write_err;
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Serialize};
28
29use crate::consensus::Params;
30use crate::constants::ChainHash;
31use crate::p2p::Magic;
32use crate::prelude::*;
33
34/// What kind of network we are on.
35#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
36pub enum NetworkKind {
37    /// The Bitcoin mainnet network.
38    Main,
39    /// Some kind of testnet network.
40    Test,
41}
42
43// We explicitly do not provide `is_testnet`, using `!network.is_mainnet()` is less
44// ambiguous due to confusion caused by signet/testnet/regtest.
45impl NetworkKind {
46    /// Returns true if this is real mainnet bitcoin.
47    pub fn is_mainnet(&self) -> bool { *self == NetworkKind::Main }
48}
49
50impl From<Network> for NetworkKind {
51    fn from(n: Network) -> Self {
52        use Network::*;
53
54        match n {
55            Bitcoin => NetworkKind::Main,
56            Testnet | Testnet4 | Signet | Regtest => NetworkKind::Test,
57        }
58    }
59}
60
61/// The cryptocurrency network to act on.
62///
63/// This is an exhaustive enum, meaning that we cannot add any future networks without defining a
64/// new, incompatible version of this type. If you are using this type directly and wish to support the
65/// new network, this will be a breaking change to your APIs and likely require changes in your code.
66///
67/// If you are concerned about forward compatibility, consider using `T: Into<Params>` instead of
68/// this type as a parameter to functions in your public API, or directly using the `Params` type.
69// For extensive discussion on the usage of `non_exhaustive` please see:
70// https://github.com/rust-bitcoin/rust-bitcoin/issues/2225
71#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)]
72#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
73#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
74#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
75pub enum Network {
76    /// Mainnet Bitcoin.
77    Bitcoin,
78    /// Bitcoin's testnet network. (In future versions this will be combined
79    /// into a single variant containing the version)
80    Testnet,
81    /// Bitcoin's testnet4 network. (In future versions this will be combined
82    /// into a single variant containing the version)
83    Testnet4,
84    /// Bitcoin's signet network.
85    Signet,
86    /// Bitcoin's regtest network.
87    Regtest,
88}
89
90impl Network {
91    /// Creates a `Network` from the magic bytes.
92    ///
93    /// # Examples
94    ///
95    /// ```rust
96    /// use bitcoin::p2p::Magic;
97    /// use bitcoin::Network;
98    ///
99    /// assert_eq!(Ok(Network::Bitcoin), Network::try_from(Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9])));
100    /// assert_eq!(None, Network::from_magic(Magic::from_bytes([0xFF, 0xFF, 0xFF, 0xFF])));
101    /// ```
102    pub fn from_magic(magic: Magic) -> Option<Network> { Network::try_from(magic).ok() }
103
104    /// Return the network magic bytes, which should be encoded little-endian
105    /// at the start of every message
106    ///
107    /// # Examples
108    ///
109    /// ```rust
110    /// use bitcoin::p2p::Magic;
111    /// use bitcoin::Network;
112    ///
113    /// let network = Network::Bitcoin;
114    /// assert_eq!(network.magic(), Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9]));
115    /// ```
116    pub fn magic(self) -> Magic { Magic::from(self) }
117
118    /// Converts a `Network` to its equivalent `bitcoind -chain` argument name.
119    ///
120    /// ```bash
121    /// $ bitcoin-23.0/bin/bitcoind --help | grep -C 3 '\-chain=<chain>'
122    /// Chain selection options:
123    ///
124    /// -chain=<chain>
125    /// Use the chain <chain> (default: main). Allowed values: main, test, signet, regtest
126    /// ```
127    pub fn to_core_arg(self) -> &'static str {
128        match self {
129            Network::Bitcoin => "main",
130            // For user-side compatibility, testnet3 is retained as test
131            Network::Testnet => "test",
132            Network::Testnet4 => "testnet4",
133            Network::Signet => "signet",
134            Network::Regtest => "regtest",
135        }
136    }
137
138    /// Converts a `bitcoind -chain` argument name to its equivalent `Network`.
139    ///
140    /// ```bash
141    /// $ bitcoin-23.0/bin/bitcoind --help | grep -C 3 '\-chain=<chain>'
142    /// Chain selection options:
143    ///
144    /// -chain=<chain>
145    /// Use the chain <chain> (default: main). Allowed values: main, test, signet, regtest
146    /// ```
147    pub fn from_core_arg(core_arg: &str) -> Result<Self, ParseNetworkError> {
148        use Network::*;
149
150        let network = match core_arg {
151            "main" => Bitcoin,
152            "test" => Testnet,
153            "testnet4" => Testnet4,
154            "signet" => Signet,
155            "regtest" => Regtest,
156            _ => return Err(ParseNetworkError(core_arg.to_owned())),
157        };
158        Ok(network)
159    }
160
161    /// Return the network's chain hash (genesis block hash).
162    ///
163    /// # Examples
164    ///
165    /// ```rust
166    /// use bitcoin::Network;
167    /// use bitcoin::blockdata::constants::ChainHash;
168    ///
169    /// let network = Network::Bitcoin;
170    /// assert_eq!(network.chain_hash(), ChainHash::BITCOIN);
171    /// ```
172    pub fn chain_hash(self) -> ChainHash { ChainHash::using_genesis_block_const(self) }
173
174    /// Creates a `Network` from the chain hash (genesis block hash).
175    ///
176    /// # Examples
177    ///
178    /// ```rust
179    /// use bitcoin::Network;
180    /// use bitcoin::blockdata::constants::ChainHash;
181    ///
182    /// assert_eq!(Ok(Network::Bitcoin), Network::try_from(ChainHash::BITCOIN));
183    /// ```
184    pub fn from_chain_hash(chain_hash: ChainHash) -> Option<Network> {
185        Network::try_from(chain_hash).ok()
186    }
187
188    /// Returns the associated network parameters.
189    pub const fn params(self) -> &'static Params {
190        match self {
191            Network::Bitcoin => &Params::BITCOIN,
192            Network::Testnet => &Params::TESTNET3,
193            Network::Testnet4 => &Params::TESTNET4,
194            Network::Signet => &Params::SIGNET,
195            Network::Regtest => &Params::REGTEST,
196        }
197    }
198
199    /// Returns a string representation of the `Network` enum variant.
200    /// This is useful for displaying the network type as a string.
201    const fn as_display_str(self) -> &'static str {
202        match self {
203            Network::Bitcoin => "bitcoin",
204            Network::Testnet => "testnet",
205            Network::Testnet4 => "testnet4",
206            Network::Signet => "signet",
207            Network::Regtest => "regtest",
208        }
209    }
210}
211
212#[cfg(feature = "serde")]
213pub mod as_core_arg {
214    //! Module for serialization/deserialization of network variants into/from Bitcoin Core values
215    #![allow(missing_docs)]
216
217    use crate::Network;
218
219    pub fn serialize<S>(network: &Network, serializer: S) -> Result<S::Ok, S::Error>
220    where
221        S: serde::Serializer,
222    {
223        serializer.serialize_str(network.to_core_arg())
224    }
225
226    pub fn deserialize<'de, D>(deserializer: D) -> Result<Network, D::Error>
227    where
228        D: serde::Deserializer<'de>,
229    {
230        struct NetworkVisitor;
231
232        impl<'de> serde::de::Visitor<'de> for NetworkVisitor {
233            type Value = Network;
234
235            fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
236                Network::from_core_arg(s).map_err(|_| {
237                    E::invalid_value(
238                        serde::de::Unexpected::Str(s),
239                        &"bitcoin network encoded as a string (either main, test, testnet4, signet or regtest)",
240                    )
241                })
242            }
243
244            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
245                write!(
246                    formatter,
247                    "bitcoin network encoded as a string (either main, test, testnet4, signet or regtest)"
248                )
249            }
250        }
251
252        deserializer.deserialize_str(NetworkVisitor)
253    }
254}
255
256/// An error in parsing network string.
257#[derive(Debug, Clone, PartialEq, Eq)]
258#[non_exhaustive]
259pub struct ParseNetworkError(String);
260
261impl fmt::Display for ParseNetworkError {
262    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
263        write_err!(f, "failed to parse {} as network", self.0; self)
264    }
265}
266
267#[cfg(feature = "std")]
268impl std::error::Error for ParseNetworkError {
269    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
270}
271
272impl FromStr for Network {
273    type Err = ParseNetworkError;
274
275    #[inline]
276    fn from_str(s: &str) -> Result<Self, Self::Err> {
277        match s {
278            "bitcoin" => Ok(Network::Bitcoin),
279            // For user-side compatibility, testnet3 is retained as testnet
280            "testnet" => Ok(Network::Testnet),
281            "testnet4" => Ok(Network::Testnet4),
282            "signet" => Ok(Network::Signet),
283            "regtest" => Ok(Network::Regtest),
284            _ => Err(ParseNetworkError(s.to_owned())),
285        }
286    }
287}
288
289impl fmt::Display for Network {
290    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
291        write!(f, "{}", self.as_display_str())
292    }
293}
294
295/// Error in parsing network from chain hash.
296#[derive(Debug, Clone, PartialEq, Eq)]
297#[non_exhaustive]
298pub struct UnknownChainHashError(ChainHash);
299
300impl Display for UnknownChainHashError {
301    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
302        write!(f, "unknown chain hash: {}", self.0)
303    }
304}
305
306#[cfg(feature = "std")]
307impl std::error::Error for UnknownChainHashError {
308    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
309}
310
311impl TryFrom<ChainHash> for Network {
312    type Error = UnknownChainHashError;
313
314    fn try_from(chain_hash: ChainHash) -> Result<Self, Self::Error> {
315        match chain_hash {
316            // Note: any new network entries must be matched against here.
317            ChainHash::BITCOIN => Ok(Network::Bitcoin),
318            ChainHash::TESTNET3 => Ok(Network::Testnet),
319            ChainHash::TESTNET4 => Ok(Network::Testnet4),
320            ChainHash::SIGNET => Ok(Network::Signet),
321            ChainHash::REGTEST => Ok(Network::Regtest),
322            _ => Err(UnknownChainHashError(chain_hash)),
323        }
324    }
325}
326
327#[cfg(test)]
328mod tests {
329    use super::Network;
330    use crate::consensus::encode::{deserialize, serialize};
331    use crate::p2p::ServiceFlags;
332
333    #[test]
334    fn serialize_test() {
335        assert_eq!(serialize(&Network::Bitcoin.magic()), &[0xf9, 0xbe, 0xb4, 0xd9]);
336        assert_eq!(
337            serialize(&Network::Testnet.magic()),
338            &[0x0b, 0x11, 0x09, 0x07]
339        );
340        assert_eq!(
341            serialize(&Network::Testnet4.magic()),
342            &[0x1c, 0x16, 0x3f, 0x28]
343        );
344        assert_eq!(serialize(&Network::Signet.magic()), &[0x0a, 0x03, 0xcf, 0x40]);
345        assert_eq!(serialize(&Network::Regtest.magic()), &[0xfa, 0xbf, 0xb5, 0xda]);
346
347        assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.magic()));
348        assert_eq!(
349            deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(),
350            Some(Network::Testnet.magic())
351        );
352        assert_eq!(
353            deserialize(&[0x1c, 0x16, 0x3f, 0x28]).ok(),
354            Some(Network::Testnet4.magic())
355        );
356        assert_eq!(deserialize(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.magic()));
357        assert_eq!(deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.magic()));
358    }
359
360    #[test]
361    fn string_test() {
362        assert_eq!(Network::Bitcoin.to_string(), "bitcoin");
363        assert_eq!(Network::Testnet.to_string(), "testnet");
364        assert_eq!(Network::Testnet4.to_string(), "testnet4");
365        assert_eq!(Network::Regtest.to_string(), "regtest");
366        assert_eq!(Network::Signet.to_string(), "signet");
367
368        assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Bitcoin);
369        assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet);
370        assert_eq!("testnet4".parse::<Network>().unwrap(), Network::Testnet4);
371        assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest);
372        assert_eq!("signet".parse::<Network>().unwrap(), Network::Signet);
373        assert!("fakenet".parse::<Network>().is_err());
374    }
375
376    #[test]
377    fn service_flags_test() {
378        let all = [
379            ServiceFlags::NETWORK,
380            ServiceFlags::GETUTXO,
381            ServiceFlags::BLOOM,
382            ServiceFlags::WITNESS,
383            ServiceFlags::COMPACT_FILTERS,
384            ServiceFlags::NETWORK_LIMITED,
385            ServiceFlags::P2P_V2,
386        ];
387
388        let mut flags = ServiceFlags::NONE;
389        for f in all.iter() {
390            assert!(!flags.has(*f));
391        }
392
393        flags |= ServiceFlags::WITNESS;
394        assert_eq!(flags, ServiceFlags::WITNESS);
395
396        let mut flags2 = flags | ServiceFlags::GETUTXO;
397        for f in all.iter() {
398            assert_eq!(flags2.has(*f), *f == ServiceFlags::WITNESS || *f == ServiceFlags::GETUTXO);
399        }
400
401        flags2 ^= ServiceFlags::WITNESS;
402        assert_eq!(flags2, ServiceFlags::GETUTXO);
403
404        flags2 |= ServiceFlags::COMPACT_FILTERS;
405        flags2 ^= ServiceFlags::GETUTXO;
406        assert_eq!(flags2, ServiceFlags::COMPACT_FILTERS);
407
408        // Test formatting.
409        assert_eq!("ServiceFlags(NONE)", ServiceFlags::NONE.to_string());
410        assert_eq!("ServiceFlags(WITNESS)", ServiceFlags::WITNESS.to_string());
411        let flag = ServiceFlags::WITNESS | ServiceFlags::BLOOM | ServiceFlags::NETWORK;
412        assert_eq!("ServiceFlags(NETWORK|BLOOM|WITNESS)", flag.to_string());
413        let flag = ServiceFlags::WITNESS | 0xf0.into();
414        assert_eq!("ServiceFlags(WITNESS|COMPACT_FILTERS|0xb0)", flag.to_string());
415    }
416
417    #[test]
418    #[cfg(feature = "serde")]
419    fn serde_roundtrip() {
420        use Network::*;
421        let tests = vec![
422            (Bitcoin, "bitcoin"),
423            (Testnet, "testnet"),
424            (Testnet4, "testnet4"),
425            (Signet, "signet"),
426            (Regtest, "regtest"),
427        ];
428
429        for tc in tests {
430            let network = tc.0;
431
432            let want = format!("\"{}\"", tc.1);
433            let got = serde_json::to_string(&tc.0).expect("failed to serialize network");
434            assert_eq!(got, want);
435
436            let back: Network = serde_json::from_str(&got).expect("failed to deserialize network");
437            assert_eq!(back, network);
438        }
439    }
440
441    #[test]
442    fn from_to_core_arg() {
443        let expected_pairs = [
444            (Network::Bitcoin, "main"),
445            (Network::Testnet, "test"),
446            (Network::Testnet4, "testnet4"),
447            (Network::Regtest, "regtest"),
448            (Network::Signet, "signet"),
449        ];
450
451        for (net, core_arg) in &expected_pairs {
452            assert_eq!(Network::from_core_arg(core_arg), Ok(*net));
453            assert_eq!(net.to_core_arg(), *core_arg);
454        }
455    }
456
457    #[cfg(feature = "serde")]
458    #[test]
459    fn serde_as_core_arg() {
460        #[derive(Serialize, Deserialize, PartialEq, Debug)]
461        #[serde(crate = "actual_serde")]
462        struct T {
463            #[serde(with = "crate::network::as_core_arg")]
464            pub network: Network,
465        }
466
467        serde_test::assert_tokens(
468            &T { network: Network::Bitcoin },
469            &[
470                serde_test::Token::Struct { name: "T", len: 1 },
471                serde_test::Token::Str("network"),
472                serde_test::Token::Str("main"),
473                serde_test::Token::StructEnd,
474            ],
475        );
476    }
477}