2022-06-29 04:05:31 +00:00
|
|
|
// SPDX-License-Identifier: CC0-1.0
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2021-11-05 21:58:18 +00:00
|
|
|
//! Bitcoin network constants.
|
2014-07-18 13:56:17 +00:00
|
|
|
//!
|
|
|
|
//! This module provides various constants relating to the Bitcoin network
|
|
|
|
//! protocol, such as protocol versioning and magic header bytes.
|
|
|
|
//!
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
//! The [`Network`][1] type implements the [`Decodable`][2] and
|
|
|
|
//! [`Encodable`][3] traits and encodes the magic bytes of the given
|
2021-11-05 21:58:18 +00:00
|
|
|
//! network.
|
2018-08-10 17:09:22 +00:00
|
|
|
//!
|
|
|
|
//! [1]: enum.Network.html
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
//! [2]: ../../consensus/encode/trait.Decodable.html
|
|
|
|
//! [3]: ../../consensus/encode/trait.Encodable.html
|
2018-08-10 17:09:22 +00:00
|
|
|
//!
|
|
|
|
//! # Example: encoding a network's magic bytes
|
|
|
|
//!
|
|
|
|
//! ```rust
|
2023-05-24 23:14:42 +00:00
|
|
|
//! use bitcoin::p2p::constants::Network;
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
//! use bitcoin::consensus::encode::serialize;
|
2018-08-10 17:09:22 +00:00
|
|
|
//!
|
|
|
|
//! let network = Network::Bitcoin;
|
2019-05-23 20:28:10 +00:00
|
|
|
//! let bytes = serialize(&network.magic());
|
2018-08-10 17:09:22 +00:00
|
|
|
//!
|
|
|
|
//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]);
|
|
|
|
//! ```
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2022-11-15 23:23:01 +00:00
|
|
|
use core::borrow::{Borrow, BorrowMut};
|
|
|
|
use core::convert::TryFrom;
|
2023-05-31 06:41:20 +00:00
|
|
|
use core::fmt;
|
2022-11-02 22:36:37 +00:00
|
|
|
use core::fmt::Display;
|
2022-09-20 05:27:25 +00:00
|
|
|
use core::str::FromStr;
|
|
|
|
|
2023-07-21 00:38:34 +00:00
|
|
|
use hex::FromHex;
|
2023-03-28 01:16:47 +00:00
|
|
|
use internals::{debug_from_display, write_err};
|
2022-09-20 05:27:25 +00:00
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
use serde::{Deserialize, Serialize};
|
2019-11-22 00:42:15 +00:00
|
|
|
|
2022-11-15 23:23:01 +00:00
|
|
|
use crate::consensus::encode::{self, Decodable, Encodable};
|
2023-02-27 06:20:57 +00:00
|
|
|
use crate::constants::ChainHash;
|
2022-11-15 23:23:01 +00:00
|
|
|
use crate::error::impl_std_error;
|
2022-05-02 22:13:57 +00:00
|
|
|
use crate::io;
|
2022-09-28 00:32:47 +00:00
|
|
|
use crate::prelude::{String, ToOwned};
|
2019-11-22 00:42:15 +00:00
|
|
|
|
2022-09-20 05:27:25 +00:00
|
|
|
/// The cryptocurrency network to act on.
|
|
|
|
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)]
|
|
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
|
|
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
|
|
|
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub enum Network {
|
|
|
|
/// Mainnet Bitcoin.
|
|
|
|
Bitcoin,
|
|
|
|
/// Bitcoin's testnet network.
|
|
|
|
Testnet,
|
|
|
|
/// Bitcoin's signet network.
|
|
|
|
Signet,
|
|
|
|
/// Bitcoin's regtest network.
|
|
|
|
Regtest,
|
2015-01-18 18:16:01 +00:00
|
|
|
}
|
2014-08-03 13:03:00 +00:00
|
|
|
|
2018-08-10 17:09:22 +00:00
|
|
|
impl Network {
|
|
|
|
/// Creates a `Network` from the magic bytes.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
2023-05-24 23:14:42 +00:00
|
|
|
/// use bitcoin::p2p::constants::{Network, Magic};
|
2022-09-28 00:32:47 +00:00
|
|
|
/// use std::convert::TryFrom;
|
2018-08-10 17:09:22 +00:00
|
|
|
///
|
2022-09-28 00:32:47 +00:00
|
|
|
/// assert_eq!(Ok(Network::Bitcoin), Network::try_from(Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9])));
|
|
|
|
/// assert_eq!(None, Network::from_magic(Magic::from_bytes([0xFF, 0xFF, 0xFF, 0xFF])));
|
2018-08-10 17:09:22 +00:00
|
|
|
/// ```
|
2022-11-15 23:23:01 +00:00
|
|
|
pub fn from_magic(magic: Magic) -> Option<Network> { Network::try_from(magic).ok() }
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2018-08-10 17:09:22 +00:00
|
|
|
/// Return the network magic bytes, which should be encoded little-endian
|
|
|
|
/// at the start of every message
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
2023-05-24 23:14:42 +00:00
|
|
|
/// use bitcoin::p2p::constants::{Network, Magic};
|
2018-08-10 17:09:22 +00:00
|
|
|
///
|
|
|
|
/// let network = Network::Bitcoin;
|
2022-09-28 00:32:47 +00:00
|
|
|
/// assert_eq!(network.magic(), Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9]));
|
2018-08-10 17:09:22 +00:00
|
|
|
/// ```
|
2022-11-15 23:23:01 +00:00
|
|
|
pub fn magic(self) -> Magic { Magic::from(self) }
|
2022-11-17 22:25:00 +00:00
|
|
|
|
|
|
|
/// Converts a `Network` to its equivalent `bitcoind -chain` argument name.
|
|
|
|
///
|
2022-12-01 20:24:42 +00:00
|
|
|
/// ```bash
|
2022-11-17 22:25:00 +00:00
|
|
|
/// $ bitcoin-23.0/bin/bitcoind --help | grep -C 3 '\-chain=<chain>'
|
|
|
|
/// Chain selection options:
|
|
|
|
///
|
|
|
|
/// -chain=<chain>
|
|
|
|
/// Use the chain <chain> (default: main). Allowed values: main, test, signet, regtest
|
|
|
|
/// ```
|
|
|
|
pub fn to_core_arg(self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
Network::Bitcoin => "main",
|
|
|
|
Network::Testnet => "test",
|
|
|
|
Network::Signet => "signet",
|
|
|
|
Network::Regtest => "regtest",
|
|
|
|
}
|
|
|
|
}
|
2022-12-01 11:05:40 +00:00
|
|
|
|
|
|
|
/// Converts a `bitcoind -chain` argument name to its equivalent `Network`.
|
|
|
|
///
|
|
|
|
/// ```bash
|
|
|
|
/// $ bitcoin-23.0/bin/bitcoind --help | grep -C 3 '\-chain=<chain>'
|
|
|
|
/// Chain selection options:
|
|
|
|
///
|
|
|
|
/// -chain=<chain>
|
|
|
|
/// Use the chain <chain> (default: main). Allowed values: main, test, signet, regtest
|
|
|
|
/// ```
|
|
|
|
pub fn from_core_arg(core_arg: &str) -> Result<Self, ParseNetworkError> {
|
|
|
|
use Network::*;
|
|
|
|
|
|
|
|
let network = match core_arg {
|
2022-10-19 16:51:41 +00:00
|
|
|
"main" => Bitcoin,
|
|
|
|
"test" => Testnet,
|
|
|
|
"signet" => Signet,
|
|
|
|
"regtest" => Regtest,
|
|
|
|
_ => return Err(ParseNetworkError(core_arg.to_owned())),
|
2022-12-01 11:05:40 +00:00
|
|
|
};
|
|
|
|
Ok(network)
|
|
|
|
}
|
2023-02-27 06:20:57 +00:00
|
|
|
|
|
|
|
/// Return the network's chain hash (genesis block hash).
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
2023-05-24 23:14:42 +00:00
|
|
|
/// use bitcoin::p2p::constants::Network;
|
2023-02-27 06:20:57 +00:00
|
|
|
/// use bitcoin::blockdata::constants::ChainHash;
|
|
|
|
///
|
|
|
|
/// let network = Network::Bitcoin;
|
|
|
|
/// assert_eq!(network.chain_hash(), ChainHash::BITCOIN);
|
|
|
|
/// ```
|
2022-11-02 22:36:37 +00:00
|
|
|
pub fn chain_hash(self) -> ChainHash { ChainHash::using_genesis_block(self) }
|
2023-02-27 06:20:57 +00:00
|
|
|
|
|
|
|
/// Creates a `Network` from the chain hash (genesis block hash).
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
2023-05-24 23:14:42 +00:00
|
|
|
/// use bitcoin::p2p::constants::Network;
|
2023-02-27 06:20:57 +00:00
|
|
|
/// use bitcoin::blockdata::constants::ChainHash;
|
|
|
|
/// use std::convert::TryFrom;
|
|
|
|
///
|
|
|
|
/// assert_eq!(Ok(Network::Bitcoin), Network::try_from(ChainHash::BITCOIN));
|
|
|
|
/// ```
|
2022-11-02 22:36:37 +00:00
|
|
|
pub fn from_chain_hash(chain_hash: ChainHash) -> Option<Network> {
|
|
|
|
Network::try_from(chain_hash).ok()
|
|
|
|
}
|
2022-09-20 05:27:25 +00:00
|
|
|
}
|
|
|
|
|
2023-04-15 06:49:45 +00:00
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
pub mod as_core_arg {
|
|
|
|
//! Module for serialization/deserialization of network variants into/from Bitcoin Core values
|
|
|
|
#![allow(missing_docs)]
|
|
|
|
|
|
|
|
use serde;
|
|
|
|
|
|
|
|
use crate::Network;
|
|
|
|
|
|
|
|
pub fn serialize<S>(network: &Network, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: serde::Serializer,
|
|
|
|
{
|
|
|
|
serializer.serialize_str(network.to_core_arg())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Network, D::Error>
|
|
|
|
where
|
|
|
|
D: serde::Deserializer<'de>,
|
|
|
|
{
|
|
|
|
struct NetworkVisitor;
|
|
|
|
|
|
|
|
impl<'de> serde::de::Visitor<'de> for NetworkVisitor {
|
|
|
|
type Value = Network;
|
|
|
|
|
|
|
|
fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
|
|
|
|
Network::from_core_arg(s).map_err(|_| {
|
|
|
|
E::invalid_value(
|
|
|
|
serde::de::Unexpected::Str(s),
|
|
|
|
&"bitcoin network encoded as a string (either main, test, signet or regtest)",
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
write!(
|
|
|
|
formatter,
|
|
|
|
"bitcoin network encoded as a string (either main, test, signet or regtest)"
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
deserializer.deserialize_str(NetworkVisitor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-10 08:37:14 +00:00
|
|
|
/// An error in parsing network string.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub struct ParseNetworkError(String);
|
|
|
|
|
|
|
|
impl fmt::Display for ParseNetworkError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
write_err!(f, "failed to parse {} as network", self.0; self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl_std_error!(ParseNetworkError);
|
|
|
|
|
2022-09-20 05:27:25 +00:00
|
|
|
impl FromStr for Network {
|
2022-10-10 08:37:14 +00:00
|
|
|
type Err = ParseNetworkError;
|
|
|
|
|
2022-09-20 05:27:25 +00:00
|
|
|
#[inline]
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
use Network::*;
|
|
|
|
|
|
|
|
let network = match s {
|
|
|
|
"bitcoin" => Bitcoin,
|
|
|
|
"testnet" => Testnet,
|
|
|
|
"signet" => Signet,
|
|
|
|
"regtest" => Regtest,
|
2022-11-15 23:23:01 +00:00
|
|
|
_ => return Err(ParseNetworkError(s.to_owned())),
|
2022-09-20 05:27:25 +00:00
|
|
|
};
|
|
|
|
Ok(network)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-28 00:32:47 +00:00
|
|
|
impl fmt::Display for Network {
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
use Network::*;
|
|
|
|
|
|
|
|
let s = match *self {
|
|
|
|
Bitcoin => "bitcoin",
|
|
|
|
Testnet => "testnet",
|
|
|
|
Signet => "signet",
|
|
|
|
Regtest => "regtest",
|
|
|
|
};
|
|
|
|
write!(f, "{}", s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-27 06:20:57 +00:00
|
|
|
/// Error in parsing network from chain hash.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub struct UnknownChainHash(ChainHash);
|
|
|
|
|
|
|
|
impl Display for UnknownChainHash {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "unknown chain hash: {}", self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_std_error!(UnknownChainHash);
|
|
|
|
|
|
|
|
impl TryFrom<ChainHash> for Network {
|
|
|
|
type Error = UnknownChainHash;
|
|
|
|
|
|
|
|
fn try_from(chain_hash: ChainHash) -> Result<Self, Self::Error> {
|
|
|
|
match chain_hash {
|
|
|
|
// Note: any new network entries must be matched against here.
|
|
|
|
ChainHash::BITCOIN => Ok(Network::Bitcoin),
|
|
|
|
ChainHash::TESTNET => Ok(Network::Testnet),
|
|
|
|
ChainHash::SIGNET => Ok(Network::Signet),
|
|
|
|
ChainHash::REGTEST => Ok(Network::Regtest),
|
|
|
|
_ => Err(UnknownChainHash(chain_hash)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-28 00:32:47 +00:00
|
|
|
/// Network magic bytes to identify the cryptocurrency network the message was intended for.
|
|
|
|
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
|
|
|
|
pub struct Magic([u8; 4]);
|
|
|
|
|
|
|
|
impl Magic {
|
|
|
|
/// Bitcoin mainnet network magic bytes.
|
|
|
|
pub const BITCOIN: Self = Self([0xF9, 0xBE, 0xB4, 0xD9]);
|
|
|
|
/// Bitcoin testnet network magic bytes.
|
|
|
|
pub const TESTNET: Self = Self([0x0B, 0x11, 0x09, 0x07]);
|
|
|
|
/// Bitcoin signet network magic bytes.
|
|
|
|
pub const SIGNET: Self = Self([0x0A, 0x03, 0xCF, 0x40]);
|
|
|
|
/// Bitcoin regtest network magic bytes.
|
|
|
|
pub const REGTEST: Self = Self([0xFA, 0xBF, 0xB5, 0xDA]);
|
|
|
|
|
|
|
|
/// Create network magic from bytes.
|
2022-11-15 23:23:01 +00:00
|
|
|
pub fn from_bytes(bytes: [u8; 4]) -> Magic { Magic(bytes) }
|
2022-09-28 00:32:47 +00:00
|
|
|
|
|
|
|
/// Get network magic bytes.
|
2022-11-15 23:23:01 +00:00
|
|
|
pub fn to_bytes(self) -> [u8; 4] { self.0 }
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// An error in parsing magic bytes.
|
2023-07-27 01:10:22 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2022-09-28 00:32:47 +00:00
|
|
|
pub struct ParseMagicError {
|
|
|
|
/// The error that occurred when parsing the string.
|
2023-07-21 00:38:34 +00:00
|
|
|
error: hex::HexToArrayError,
|
2022-09-28 00:32:47 +00:00
|
|
|
/// The byte string that failed to parse.
|
2022-11-15 23:23:01 +00:00
|
|
|
magic: String,
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for Magic {
|
|
|
|
type Err = ParseMagicError;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Magic, Self::Err> {
|
|
|
|
match <[u8; 4]>::from_hex(s) {
|
|
|
|
Ok(magic) => Ok(Magic::from_bytes(magic)),
|
2022-11-15 23:23:01 +00:00
|
|
|
Err(e) => Err(ParseMagicError { error: e, magic: s.to_owned() }),
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Network> for Magic {
|
|
|
|
fn from(network: Network) -> Magic {
|
|
|
|
match network {
|
|
|
|
// Note: new network entries must explicitly be matched in `try_from` below.
|
|
|
|
Network::Bitcoin => Magic::BITCOIN,
|
|
|
|
Network::Testnet => Magic::TESTNET,
|
|
|
|
Network::Signet => Magic::SIGNET,
|
2022-11-15 23:23:01 +00:00
|
|
|
Network::Regtest => Magic::REGTEST,
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-27 06:33:20 +00:00
|
|
|
/// Error in creating a Network from Magic bytes.
|
2022-09-28 00:32:47 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub struct UnknownMagic(Magic);
|
|
|
|
|
|
|
|
impl TryFrom<Magic> for Network {
|
|
|
|
type Error = UnknownMagic;
|
|
|
|
|
|
|
|
fn try_from(magic: Magic) -> Result<Self, Self::Error> {
|
|
|
|
match magic {
|
|
|
|
// Note: any new network entries must be matched against here.
|
|
|
|
Magic::BITCOIN => Ok(Network::Bitcoin),
|
|
|
|
Magic::TESTNET => Ok(Network::Testnet),
|
|
|
|
Magic::SIGNET => Ok(Network::Signet),
|
|
|
|
Magic::REGTEST => Ok(Network::Regtest),
|
2022-11-15 23:23:01 +00:00
|
|
|
_ => Err(UnknownMagic(magic)),
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Magic {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
2023-07-21 00:38:34 +00:00
|
|
|
hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?;
|
2022-09-28 00:32:47 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
debug_from_display!(Magic);
|
|
|
|
|
|
|
|
impl fmt::LowerHex for Magic {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
2023-07-21 00:38:34 +00:00
|
|
|
hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?;
|
2022-09-28 00:32:47 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::UpperHex for Magic {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
2023-07-21 00:38:34 +00:00
|
|
|
hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Upper)?;
|
2022-09-28 00:32:47 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Encodable for Magic {
|
|
|
|
fn consensus_encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
|
|
|
self.0.consensus_encode(writer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Decodable for Magic {
|
|
|
|
fn consensus_decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
|
|
|
|
Ok(Magic(Decodable::consensus_decode(reader)?))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<[u8]> for Magic {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn as_ref(&self) -> &[u8] { &self.0 }
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<[u8; 4]> for Magic {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn as_ref(&self) -> &[u8; 4] { &self.0 }
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
|
2022-09-29 06:04:37 +00:00
|
|
|
impl AsMut<[u8]> for Magic {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn as_mut(&mut self) -> &mut [u8] { &mut self.0 }
|
2022-09-29 06:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AsMut<[u8; 4]> for Magic {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn as_mut(&mut self) -> &mut [u8; 4] { &mut self.0 }
|
2022-09-29 06:04:37 +00:00
|
|
|
}
|
|
|
|
|
2022-09-28 00:32:47 +00:00
|
|
|
impl Borrow<[u8]> for Magic {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn borrow(&self) -> &[u8] { &self.0 }
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Borrow<[u8; 4]> for Magic {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn borrow(&self) -> &[u8; 4] { &self.0 }
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BorrowMut<[u8]> for Magic {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn borrow_mut(&mut self) -> &mut [u8] { &mut self.0 }
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BorrowMut<[u8; 4]> for Magic {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn borrow_mut(&mut self) -> &mut [u8; 4] { &mut self.0 }
|
2022-09-28 00:32:47 +00:00
|
|
|
}
|
|
|
|
|
2022-09-28 09:43:10 +00:00
|
|
|
impl fmt::Display for ParseMagicError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
write_err!(f, "failed to parse {} as network magic", self.magic; self.error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl_std_error!(ParseMagicError, error);
|
|
|
|
|
|
|
|
impl fmt::Display for UnknownMagic {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
write!(f, "unknown network magic {}", self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl_std_error!(UnknownMagic);
|
|
|
|
|
2014-08-03 13:03:00 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-09-28 00:32:47 +00:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
use std::str::FromStr;
|
2014-08-03 13:03:00 +00:00
|
|
|
|
2023-05-31 06:41:20 +00:00
|
|
|
use super::{Magic, Network};
|
2022-11-15 23:23:01 +00:00
|
|
|
use crate::consensus::encode::{deserialize, serialize};
|
2023-05-31 06:41:20 +00:00
|
|
|
use crate::p2p::ServiceFlags;
|
2022-11-15 23:23:01 +00:00
|
|
|
|
2019-05-23 20:28:10 +00:00
|
|
|
#[test]
|
|
|
|
fn serialize_test() {
|
2022-01-24 00:31:39 +00:00
|
|
|
assert_eq!(serialize(&Network::Bitcoin.magic()), &[0xf9, 0xbe, 0xb4, 0xd9]);
|
|
|
|
assert_eq!(serialize(&Network::Testnet.magic()), &[0x0b, 0x11, 0x09, 0x07]);
|
|
|
|
assert_eq!(serialize(&Network::Signet.magic()), &[0x0a, 0x03, 0xcf, 0x40]);
|
|
|
|
assert_eq!(serialize(&Network::Regtest.magic()), &[0xfa, 0xbf, 0xb5, 0xda]);
|
|
|
|
|
|
|
|
assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.magic()));
|
|
|
|
assert_eq!(deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet.magic()));
|
|
|
|
assert_eq!(deserialize(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.magic()));
|
|
|
|
assert_eq!(deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.magic()));
|
2019-05-23 20:28:10 +00:00
|
|
|
}
|
2018-05-16 09:22:07 +00:00
|
|
|
|
2019-11-22 00:42:15 +00:00
|
|
|
#[test]
|
|
|
|
fn string_test() {
|
|
|
|
assert_eq!(Network::Bitcoin.to_string(), "bitcoin");
|
|
|
|
assert_eq!(Network::Testnet.to_string(), "testnet");
|
|
|
|
assert_eq!(Network::Regtest.to_string(), "regtest");
|
2019-07-10 04:53:53 +00:00
|
|
|
assert_eq!(Network::Signet.to_string(), "signet");
|
2019-11-22 00:42:15 +00:00
|
|
|
|
|
|
|
assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Bitcoin);
|
|
|
|
assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet);
|
|
|
|
assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest);
|
2019-07-10 04:53:53 +00:00
|
|
|
assert_eq!("signet".parse::<Network>().unwrap(), Network::Signet);
|
2019-11-22 00:42:15 +00:00
|
|
|
assert!("fakenet".parse::<Network>().is_err());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn service_flags_test() {
|
|
|
|
let all = [
|
|
|
|
ServiceFlags::NETWORK,
|
|
|
|
ServiceFlags::GETUTXO,
|
|
|
|
ServiceFlags::BLOOM,
|
|
|
|
ServiceFlags::WITNESS,
|
2019-12-21 01:39:30 +00:00
|
|
|
ServiceFlags::COMPACT_FILTERS,
|
2019-11-22 00:42:15 +00:00
|
|
|
ServiceFlags::NETWORK_LIMITED,
|
|
|
|
];
|
|
|
|
|
|
|
|
let mut flags = ServiceFlags::NONE;
|
|
|
|
for f in all.iter() {
|
|
|
|
assert!(!flags.has(*f));
|
|
|
|
}
|
|
|
|
|
|
|
|
flags |= ServiceFlags::WITNESS;
|
|
|
|
assert_eq!(flags, ServiceFlags::WITNESS);
|
2018-05-16 09:22:07 +00:00
|
|
|
|
2019-11-22 00:42:15 +00:00
|
|
|
let mut flags2 = flags | ServiceFlags::GETUTXO;
|
|
|
|
for f in all.iter() {
|
|
|
|
assert_eq!(flags2.has(*f), *f == ServiceFlags::WITNESS || *f == ServiceFlags::GETUTXO);
|
|
|
|
}
|
|
|
|
|
|
|
|
flags2 ^= ServiceFlags::WITNESS;
|
|
|
|
assert_eq!(flags2, ServiceFlags::GETUTXO);
|
2022-01-24 00:24:32 +00:00
|
|
|
|
2019-12-21 01:39:30 +00:00
|
|
|
flags2 |= ServiceFlags::COMPACT_FILTERS;
|
|
|
|
flags2 ^= ServiceFlags::GETUTXO;
|
|
|
|
assert_eq!(flags2, ServiceFlags::COMPACT_FILTERS);
|
2019-12-05 20:13:45 +00:00
|
|
|
|
|
|
|
// Test formatting.
|
|
|
|
assert_eq!("ServiceFlags(NONE)", ServiceFlags::NONE.to_string());
|
|
|
|
assert_eq!("ServiceFlags(WITNESS)", ServiceFlags::WITNESS.to_string());
|
|
|
|
let flag = ServiceFlags::WITNESS | ServiceFlags::BLOOM | ServiceFlags::NETWORK;
|
|
|
|
assert_eq!("ServiceFlags(NETWORK|BLOOM|WITNESS)", flag.to_string());
|
|
|
|
let flag = ServiceFlags::WITNESS | 0xf0.into();
|
2019-12-21 02:36:47 +00:00
|
|
|
assert_eq!("ServiceFlags(WITNESS|COMPACT_FILTERS|0xb0)", flag.to_string());
|
2019-11-22 00:42:15 +00:00
|
|
|
}
|
2022-09-20 05:19:47 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
fn serde_roundtrip() {
|
|
|
|
use Network::*;
|
2022-11-15 23:23:01 +00:00
|
|
|
let tests = vec![
|
|
|
|
(Bitcoin, "bitcoin"),
|
|
|
|
(Testnet, "testnet"),
|
|
|
|
(Signet, "signet"),
|
|
|
|
(Regtest, "regtest"),
|
|
|
|
];
|
2022-09-20 05:19:47 +00:00
|
|
|
|
|
|
|
for tc in tests {
|
|
|
|
let network = tc.0;
|
|
|
|
|
|
|
|
let want = format!("\"{}\"", tc.1);
|
|
|
|
let got = serde_json::to_string(&tc.0).expect("failed to serialize network");
|
|
|
|
assert_eq!(got, want);
|
|
|
|
|
|
|
|
let back: Network = serde_json::from_str(&got).expect("failed to deserialize network");
|
|
|
|
assert_eq!(back, network);
|
|
|
|
}
|
|
|
|
}
|
2022-09-28 00:32:47 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn magic_from_str() {
|
|
|
|
let known_network_magic_strs = [
|
|
|
|
("f9beb4d9", Network::Bitcoin),
|
|
|
|
("0b110907", Network::Testnet),
|
|
|
|
("fabfb5da", Network::Regtest),
|
|
|
|
("0a03cf40", Network::Signet),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (magic_str, network) in &known_network_magic_strs {
|
|
|
|
let magic: Magic = Magic::from_str(magic_str).unwrap();
|
|
|
|
assert_eq!(Network::try_from(magic).unwrap(), *network);
|
|
|
|
assert_eq!(&magic.to_string(), magic_str);
|
|
|
|
}
|
|
|
|
}
|
2022-12-08 12:18:34 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_to_core_arg() {
|
|
|
|
let expected_pairs = [
|
|
|
|
(Network::Bitcoin, "main"),
|
|
|
|
(Network::Testnet, "test"),
|
|
|
|
(Network::Regtest, "regtest"),
|
|
|
|
(Network::Signet, "signet"),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (net, core_arg) in &expected_pairs {
|
|
|
|
assert_eq!(Network::from_core_arg(core_arg), Ok(*net));
|
|
|
|
assert_eq!(net.to_core_arg(), *core_arg);
|
|
|
|
}
|
|
|
|
}
|
2023-04-15 06:49:45 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
#[test]
|
|
|
|
fn serde_as_core_arg() {
|
|
|
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
|
|
#[serde(crate = "actual_serde")]
|
|
|
|
struct T {
|
2023-05-24 23:14:42 +00:00
|
|
|
#[serde(with = "crate::p2p::constants::as_core_arg")]
|
2023-04-15 06:49:45 +00:00
|
|
|
pub network: Network,
|
|
|
|
}
|
|
|
|
|
|
|
|
serde_test::assert_tokens(
|
|
|
|
&T { network: Network::Bitcoin },
|
|
|
|
&[
|
|
|
|
serde_test::Token::Struct { name: "T", len: 1 },
|
|
|
|
serde_test::Token::Str("network"),
|
|
|
|
serde_test::Token::Str("main"),
|
|
|
|
serde_test::Token::StructEnd,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
2014-08-03 13:03:00 +00:00
|
|
|
}
|