diff --git a/bitcoin/src/network/constants.rs b/bitcoin/src/network/constants.rs index 7172207d..c473ffce 100644 --- a/bitcoin/src/network/constants.rs +++ b/bitcoin/src/network/constants.rs @@ -30,12 +30,14 @@ use core::borrow::{Borrow, BorrowMut}; use core::convert::TryFrom; use core::str::FromStr; use core::{fmt, ops}; +use core::fmt::Display; use bitcoin_internals::{debug_from_display, write_err}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate::consensus::encode::{self, Decodable, Encodable}; +use crate::constants::ChainHash; use crate::error::impl_std_error; use crate::hashes::hex::{Error, FromHex}; use crate::io; @@ -141,6 +143,34 @@ impl Network { }; Ok(network) } + + /// Return the network's chain hash (genesis block hash). + /// + /// # Examples + /// + /// ```rust + /// use bitcoin::network::constants::Network; + /// use bitcoin::blockdata::constants::ChainHash; + /// + /// let network = Network::Bitcoin; + /// assert_eq!(network.chain_hash(), ChainHash::BITCOIN); + /// ``` + pub fn chain_hash(self) -> ChainHash { + ChainHash::using_genesis_block(self) + } + + /// Creates a `Network` from the chain hash (genesis block hash). + /// + /// # Examples + /// + /// ```rust + /// use bitcoin::network::constants::Network; + /// use bitcoin::blockdata::constants::ChainHash; + /// use std::convert::TryFrom; + /// + /// assert_eq!(Ok(Network::Bitcoin), Network::try_from(ChainHash::BITCOIN)); + /// ``` + pub fn from_chain_hash(chain_hash: ChainHash) -> Option { Network::try_from(chain_hash).ok() } } /// An error in parsing network string. @@ -186,6 +216,33 @@ impl fmt::Display for Network { } } +/// 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 for Network { + type Error = UnknownChainHash; + + fn try_from(chain_hash: ChainHash) -> Result { + 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)), + } + } +} + /// 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]);