#[cfg(feature = "std")]
pub mod address;
#[cfg(feature = "std")]
pub mod message;
#[cfg(feature = "std")]
pub mod message_blockdata;
#[cfg(feature = "std")]
pub mod message_bloom;
#[cfg(feature = "std")]
pub mod message_compact_blocks;
#[cfg(feature = "std")]
pub mod message_filter;
#[cfg(feature = "std")]
pub mod message_network;
use core::str::FromStr;
use core::{fmt, ops};
use hex::FromHex;
use internals::{debug_from_display, write_err};
use io::{Read, Write};
use crate::consensus::encode::{self, Decodable, Encodable};
use crate::consensus::Params;
use crate::prelude::*;
use crate::network::Network;
#[rustfmt::skip]
#[doc(inline)]
#[cfg(feature = "std")]
pub use self::address::Address;
pub const PROTOCOL_VERSION: u32 = 70001;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ServiceFlags(u64);
impl ServiceFlags {
pub const NONE: ServiceFlags = ServiceFlags(0);
pub const NETWORK: ServiceFlags = ServiceFlags(1 << 0);
pub const GETUTXO: ServiceFlags = ServiceFlags(1 << 1);
pub const BLOOM: ServiceFlags = ServiceFlags(1 << 2);
pub const WITNESS: ServiceFlags = ServiceFlags(1 << 3);
pub const COMPACT_FILTERS: ServiceFlags = ServiceFlags(1 << 6);
pub const NETWORK_LIMITED: ServiceFlags = ServiceFlags(1 << 10);
pub const P2P_V2: ServiceFlags = ServiceFlags(1 << 11);
pub fn add(&mut self, other: ServiceFlags) -> ServiceFlags {
self.0 |= other.0;
*self
}
pub fn remove(&mut self, other: ServiceFlags) -> ServiceFlags {
self.0 ^= other.0;
*self
}
pub fn has(self, flags: ServiceFlags) -> bool { (self.0 | flags.0) == self.0 }
pub fn to_u64(self) -> u64 { self.0 }
}
impl fmt::LowerHex for ServiceFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
}
impl fmt::UpperHex for ServiceFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) }
}
impl fmt::Display for ServiceFlags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut flags = *self;
if flags == ServiceFlags::NONE {
return write!(f, "ServiceFlags(NONE)");
}
let mut first = true;
macro_rules! write_flag {
($f:ident) => {
if flags.has(ServiceFlags::$f) {
if !first {
write!(f, "|")?;
}
first = false;
write!(f, stringify!($f))?;
flags.remove(ServiceFlags::$f);
}
};
}
write!(f, "ServiceFlags(")?;
write_flag!(NETWORK);
write_flag!(GETUTXO);
write_flag!(BLOOM);
write_flag!(WITNESS);
write_flag!(COMPACT_FILTERS);
write_flag!(NETWORK_LIMITED);
write_flag!(P2P_V2);
if flags != ServiceFlags::NONE {
if !first {
write!(f, "|")?;
}
write!(f, "0x{:x}", flags)?;
}
write!(f, ")")
}
}
impl From<u64> for ServiceFlags {
fn from(f: u64) -> Self { ServiceFlags(f) }
}
impl From<ServiceFlags> for u64 {
fn from(flags: ServiceFlags) -> Self { flags.0 }
}
impl ops::BitOr for ServiceFlags {
type Output = Self;
fn bitor(mut self, rhs: Self) -> Self { self.add(rhs) }
}
impl ops::BitOrAssign for ServiceFlags {
fn bitor_assign(&mut self, rhs: Self) { self.add(rhs); }
}
impl ops::BitXor for ServiceFlags {
type Output = Self;
fn bitxor(mut self, rhs: Self) -> Self { self.remove(rhs) }
}
impl ops::BitXorAssign for ServiceFlags {
fn bitxor_assign(&mut self, rhs: Self) { self.remove(rhs); }
}
impl Encodable for ServiceFlags {
#[inline]
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
self.0.consensus_encode(w)
}
}
impl Decodable for ServiceFlags {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(ServiceFlags(Decodable::consensus_decode(r)?))
}
}
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct Magic([u8; 4]);
impl Magic {
pub const BITCOIN: Self = Self([0xF9, 0xBE, 0xB4, 0xD9]);
#[deprecated(since = "0.32.4", note = "Use TESTNET3 instead")]
pub const TESTNET: Self = Self([0x0B, 0x11, 0x09, 0x07]);
pub const TESTNET3: Self = Self([0x0B, 0x11, 0x09, 0x07]);
pub const TESTNET4: Self = Self([0x1c, 0x16, 0x3f, 0x28]);
pub const SIGNET: Self = Self([0x0A, 0x03, 0xCF, 0x40]);
pub const REGTEST: Self = Self([0xFA, 0xBF, 0xB5, 0xDA]);
pub fn from_bytes(bytes: [u8; 4]) -> Magic { Magic(bytes) }
pub fn to_bytes(self) -> [u8; 4] { self.0 }
pub fn from_params(params: impl AsRef<Params>) -> Self {
params.as_ref().network.into()
}
}
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)),
Err(e) => Err(ParseMagicError { error: e, magic: s.to_owned() }),
}
}
}
impl From<Network> for Magic {
fn from(network: Network) -> Magic {
match network {
Network::Bitcoin => Magic::BITCOIN,
Network::Testnet => Magic::TESTNET3,
Network::Testnet4 => Magic::TESTNET4,
Network::Signet => Magic::SIGNET,
Network::Regtest => Magic::REGTEST,
}
}
}
impl TryFrom<Magic> for Network {
type Error = UnknownMagicError;
fn try_from(magic: Magic) -> Result<Self, Self::Error> {
match magic {
Magic::BITCOIN => Ok(Network::Bitcoin),
Magic::TESTNET3 => Ok(Network::Testnet),
Magic::TESTNET4 => Ok(Network::Testnet4),
Magic::SIGNET => Ok(Network::Signet),
Magic::REGTEST => Ok(Network::Regtest),
_ => Err(UnknownMagicError(magic)),
}
}
}
impl fmt::Display for Magic {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?;
Ok(())
}
}
debug_from_display!(Magic);
impl fmt::LowerHex for Magic {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Lower)?;
Ok(())
}
}
impl fmt::UpperHex for Magic {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
hex::fmt_hex_exact!(f, 4, &self.0, hex::Case::Upper)?;
Ok(())
}
}
impl Encodable for Magic {
fn consensus_encode<W: Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
self.0.consensus_encode(writer)
}
}
impl Decodable for Magic {
fn consensus_decode<R: Read + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
Ok(Magic(Decodable::consensus_decode(reader)?))
}
}
impl AsRef<[u8]> for Magic {
fn as_ref(&self) -> &[u8] { &self.0 }
}
impl AsRef<[u8; 4]> for Magic {
fn as_ref(&self) -> &[u8; 4] { &self.0 }
}
impl AsMut<[u8]> for Magic {
fn as_mut(&mut self) -> &mut [u8] { &mut self.0 }
}
impl AsMut<[u8; 4]> for Magic {
fn as_mut(&mut self) -> &mut [u8; 4] { &mut self.0 }
}
impl Borrow<[u8]> for Magic {
fn borrow(&self) -> &[u8] { &self.0 }
}
impl Borrow<[u8; 4]> for Magic {
fn borrow(&self) -> &[u8; 4] { &self.0 }
}
impl BorrowMut<[u8]> for Magic {
fn borrow_mut(&mut self) -> &mut [u8] { &mut self.0 }
}
impl BorrowMut<[u8; 4]> for Magic {
fn borrow_mut(&mut self) -> &mut [u8; 4] { &mut self.0 }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ParseMagicError {
error: hex::HexToArrayError,
magic: String,
}
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)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseMagicError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.error) }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct UnknownMagicError(Magic);
impl fmt::Display for UnknownMagicError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "unknown network magic {}", self.0)
}
}
#[cfg(feature = "std")]
impl std::error::Error for UnknownMagicError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn service_flags_test() {
let all = [
ServiceFlags::NETWORK,
ServiceFlags::GETUTXO,
ServiceFlags::BLOOM,
ServiceFlags::WITNESS,
ServiceFlags::COMPACT_FILTERS,
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);
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);
flags2 |= ServiceFlags::COMPACT_FILTERS;
flags2 ^= ServiceFlags::GETUTXO;
assert_eq!(flags2, ServiceFlags::COMPACT_FILTERS);
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();
assert_eq!("ServiceFlags(WITNESS|COMPACT_FILTERS|0xb0)", flag.to_string());
}
#[test]
fn magic_from_str() {
let known_network_magic_strs = [
("f9beb4d9", Network::Bitcoin),
("0b110907", Network::Testnet),
("1c163f28", Network::Testnet4),
("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);
}
}
}