use std::{fmt, io, ops};
use std::str::FromStr;
use crate::consensus::encode::{self, Encodable, Decodable};
pub const PROTOCOL_VERSION: u32 = 10000;
pub const SERVICES: u64 = 0;
pub const USER_AGENT: &str = "tapyrus-rust v0.1";
#[derive(Clone, Debug, PartialEq)]
pub struct NetworkId(u32);
impl NetworkId {
pub fn magic(self) -> u32 {
(33550335 + self.0).swap_bytes()
}
pub const PRODUCTION: NetworkId = NetworkId(1);
pub const PARADIUM: NetworkId = NetworkId(101);
pub const TESTNET: NetworkId = NetworkId(1939510133);
pub const REGTEST: NetworkId = NetworkId(1905960821);
}
impl From<u32> for NetworkId {
fn from(n: u32) -> Self {
NetworkId(n)
}
}
impl FromStr for NetworkId {
type Err = std::num::ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(NetworkId::from(s.parse::<u32>()?))
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for NetworkId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_u32(self.0)
}
}
#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for NetworkId {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<NetworkId, D::Error> {
struct NetworkIdVisitor;
impl<'de> ::serde::de::Visitor<'de> for NetworkIdVisitor {
type Value = NetworkId;
fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
formatter.write_str("an integer u32")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: ::serde::de::Error,
{
Ok(NetworkId::from(v as u32))
}
}
d.deserialize_u32(NetworkIdVisitor)
}
}
user_enum! {
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum Network {
Prod <-> "prod",
Dev <-> "dev"
}
}
#[derive(Debug, Clone, Copy, 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 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 as_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);
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(val: ServiceFlags) -> Self {
val.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<S: io::Write>(
&self,
mut s: S,
) -> Result<usize, encode::Error> {
self.0.consensus_encode(&mut s)
}
}
impl Decodable for ServiceFlags {
#[inline]
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
Ok(ServiceFlags(Decodable::consensus_decode(&mut d)?))
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::{NetworkId, Network, ServiceFlags};
use crate::consensus::encode::{deserialize, serialize};
#[test]
fn serialize_test() {
assert_eq!(
serialize(&NetworkId::PRODUCTION.magic()),
&[0x01, 0xff, 0xf0, 0x00]
);
assert_eq!(
serialize(&NetworkId::TESTNET.magic()),
&[0x75, 0x9a, 0x83, 0x74]
);
assert_eq!(
serialize(&NetworkId::REGTEST.magic()),
&[0x73, 0x9a, 0x97, 0x74]
);
assert_eq!(
serialize(&NetworkId::PARADIUM.magic()),
&[0x01, 0xff, 0xf0, 0x64]
);
assert_eq!(
deserialize(&[0x01, 0xff, 0xf0, 0x00]).ok(),
Some(NetworkId::PRODUCTION.magic())
);
assert_eq!(
deserialize(&[0x75, 0x9a, 0x83, 0x74]).ok(),
Some(NetworkId::TESTNET.magic())
);
assert_eq!(
deserialize(&[0x73, 0x9a, 0x97, 0x74]).ok(),
Some(NetworkId::REGTEST.magic())
);
assert_eq!(
deserialize(&[0x01, 0xff, 0xf0, 0x64]).ok(),
Some(NetworkId::PARADIUM.magic())
);
}
#[test]
fn string_test() {
assert_eq!(Network::Prod.to_string(), "prod");
assert_eq!(Network::Dev.to_string(), "dev");
assert_eq!("prod".parse::<Network>().unwrap(), Network::Prod);
assert_eq!("dev".parse::<Network>().unwrap(), Network::Dev);
assert!("fakenet".parse::<Network>().is_err());
}
#[test]
fn network_id_from_str_test() {
assert_eq!(NetworkId::from_str("1").unwrap(), NetworkId::from(1));
}
#[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]
#[cfg(feature = "serde")]
fn test_network_id_serialize() {
serde_round_trip!(NetworkId::from(1));
}
}