Refactor and add more documentation for the `Network` type.

Signed-off-by: Jean Pierre Dudey <jeandudey@hotmail.com>
This commit is contained in:
Jean Pierre Dudey 2018-08-10 13:09:22 -04:00
parent 45c699f005
commit 7ecb6b9dea
2 changed files with 79 additions and 29 deletions

View File

@ -12,28 +12,34 @@
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. // If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
// //
//! # Network constants //! Network constants
//! //!
//! This module provides various constants relating to the Bitcoin network //! This module provides various constants relating to the Bitcoin network
//! protocol, such as protocol versioning and magic header bytes. //! protocol, such as protocol versioning and magic header bytes.
//! //!
//! The [`Network`][1] type implements the [`ConsensusDecodable`][2] and
//! [`ConsensusEncodable`][3] and encodes the magic bytes of the given
//! network
//!
//! [1]: enum.Network.html
//! [2]: ../encodable/trait.ConsensusDecodable.html
//! [3]: ../encodable/trait.ConsensusEncodable.html
//!
//! # Example: encoding a network's magic bytes
//!
//! ```rust
//! use bitcoin::network::constants::Network;
//! use bitcoin::network::serialize::serialize;
//!
//! let network = Network::Bitcoin;
//! let bytes = serialize(&network).unwrap();
//!
//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]);
//! ```
use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::serialize::{SimpleEncoder, SimpleDecoder}; use network::serialize::{SimpleEncoder, SimpleDecoder};
user_enum! {
#[derive(Copy, PartialEq, Eq, Clone, Hash)]
#[doc="The cryptocurrency to act on"]
pub enum Network {
#[doc="Classic Bitcoin"]
Bitcoin <-> "bitcoin",
#[doc="Bitcoin's testnet"]
Testnet <-> "testnet",
#[doc="Bitcoin's regtest"]
Regtest <-> "regtest"
}
}
/// Version of the protocol as appearing in network message headers /// Version of the protocol as appearing in network message headers
pub const PROTOCOL_VERSION: u32 = 70001; pub const PROTOCOL_VERSION: u32 = 70001;
/// Bitfield of services provided by this node /// Bitfield of services provided by this node
@ -41,34 +47,78 @@ pub const SERVICES: u64 = 0;
/// User agent as it appears in the version message /// User agent as it appears in the version message
pub const USER_AGENT: &'static str = "bitcoin-rust v0.1"; pub const USER_AGENT: &'static str = "bitcoin-rust v0.1";
/// Return the network magic bytes, which should be encoded little-endian user_enum! {
/// at the start of every message /// The cryptocurrency to act on
pub fn magic(network: Network) -> u32 { #[derive(Copy, PartialEq, Eq, Clone, Hash)]
match network { pub enum Network {
/// Classic Bitcoin
Bitcoin <-> "bitcoin",
/// Bitcoin's testnet
Testnet <-> "testnet",
/// Bitcoin's regtest
Regtest <-> "regtest"
}
}
impl Network {
/// Creates a `Network` from the magic bytes.
///
/// # Examples
///
/// ```rust
/// use bitcoin::network::constants::Network;
///
/// assert_eq!(Some(Network::Bitcoin), Network::from_magic(0xD9B4BEF9));
/// assert_eq!(None, Network::from_magic(0xFFFFFFFF));
/// ```
pub fn from_magic(magic: u32) -> Option<Network> {
// Note: any new entries here must be added to `magic` below
match magic {
0xD9B4BEF9 => Some(Network::Bitcoin),
0x0709110B => Some(Network::Testnet),
0xDAB5BFFA => Some(Network::Regtest),
_ => None
}
}
/// Return the network magic bytes, which should be encoded little-endian
/// at the start of every message
///
/// # Examples
///
/// ```rust
/// use bitcoin::network::constants::Network;
///
/// let network = Network::Bitcoin;
/// assert_eq!(network.magic(), 0xD9B4BEF9);
/// ```
pub fn magic(&self) -> u32 {
// Note: any new entries here must be added to `from_magic` above
match *self {
Network::Bitcoin => 0xD9B4BEF9, Network::Bitcoin => 0xD9B4BEF9,
Network::Testnet => 0x0709110B, Network::Testnet => 0x0709110B,
Network::Regtest => 0xDAB5BFFA, Network::Regtest => 0xDAB5BFFA,
// Note: any new entries here must be added to `consensus_decode` below }
} }
} }
impl<S: SimpleEncoder> ConsensusEncodable<S> for Network { impl<S: SimpleEncoder> ConsensusEncodable<S> for Network {
/// Encodes the magic bytes of `Network`.
#[inline] #[inline]
fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
magic(*self).consensus_encode(s) self.magic().consensus_encode(s)
} }
} }
impl<D: SimpleDecoder> ConsensusDecodable<D> for Network { impl<D: SimpleDecoder> ConsensusDecodable<D> for Network {
/// Decodes the magic bytes of `Network`.
#[inline] #[inline]
fn consensus_decode(d: &mut D) -> Result<Network, D::Error> { fn consensus_decode(d: &mut D) -> Result<Network, D::Error> {
let magic: u32 = try!(ConsensusDecodable::consensus_decode(d)); u32::consensus_decode(d)
match magic { .and_then(|m| {
0xD9B4BEF9 => Ok(Network::Bitcoin), Network::from_magic(m)
0x0709110B => Ok(Network::Testnet), .ok_or(d.error(format!("Unknown network (magic {:x})", m)))
0xDAB5BFFA => Ok(Network::Regtest), })
x => Err(d.error(format!("Unknown network (magic {:x})", x)))
}
} }
} }

View File

@ -90,7 +90,7 @@ impl Socket {
services: 0, services: 0,
version_nonce: rng.gen(), version_nonce: rng.gen(),
user_agent: constants::USER_AGENT.to_owned(), user_agent: constants::USER_AGENT.to_owned(),
magic: constants::magic(network) magic: network.magic(),
} }
} }