Add ServiceFlags type

This commit is contained in:
Steven Roose 2019-11-22 00:42:15 +00:00
parent 885fc39f48
commit fdf4b2f74e
No known key found for this signature in database
GPG Key ID: 2F2A88D7F8D68E87
1 changed files with 158 additions and 11 deletions

View File

@ -37,6 +37,10 @@
//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]);
//! ```
use std::{io, ops};
use consensus::encode::{self, Encodable, Decodable};
/// Version of the protocol as appearing in network message headers
pub const PROTOCOL_VERSION: u32 = 70001;
/// Bitfield of services provided by this node
@ -99,9 +103,125 @@ impl Network {
}
}
/// Flags to indicate which network services a node supports.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ServiceFlags(u64);
impl ServiceFlags {
/// NONE means no services supported.
pub const NONE: ServiceFlags = ServiceFlags(0);
/// NETWORK means that the node is capable of serving the complete block chain. It is currently
/// set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light
/// clients.
pub const NETWORK: ServiceFlags = ServiceFlags(1 << 0);
/// GETUTXO means the node is capable of responding to the getutxo protocol request. Bitcoin
/// Core does not support this but a patch set called Bitcoin XT does.
/// See BIP 64 for details on how this is implemented.
pub const GETUTXO: ServiceFlags = ServiceFlags(1 << 1);
/// BLOOM means the node is capable and willing to handle bloom-filtered connections. Bitcoin
/// Core nodes used to support this by default, without advertising this bit, but no longer do
/// as of protocol version 70011 (= NO_BLOOM_VERSION)
pub const BLOOM: ServiceFlags = ServiceFlags(1 << 2);
/// WITNESS indicates that a node can be asked for blocks and transactions including witness
/// data.
pub const WITNESS: ServiceFlags = ServiceFlags(1 << 3);
/// NETWORK_LIMITED means the same as NODE_NETWORK with the limitation of only serving the last
/// 288 (2 day) blocks.
/// See BIP159 for details on how this is implemented.
pub const NETWORK_LIMITED: ServiceFlags = ServiceFlags(1 << 10);
/// Add [ServiceFlags] together.
///
/// Returns itself.
pub fn add(&mut self, other: ServiceFlags) -> ServiceFlags {
self.0 |= other.0;
*self
}
/// Remove [ServiceFlags] from this.
///
/// Returns itself.
pub fn remove(&mut self, other: ServiceFlags) -> ServiceFlags {
self.0 ^= other.0;
*self
}
/// Check whether [ServiceFlags] are included in this one.
pub fn has(&self, flags: ServiceFlags) -> bool {
(self.0 | flags.0) == self.0
}
/// Get the integer representation of this [ServiceFlags].
pub fn as_u64(&self) -> u64 {
self.0
}
}
impl From<u64> for ServiceFlags {
fn from(f: u64) -> Self {
ServiceFlags(f)
}
}
impl Into<u64> for ServiceFlags {
fn into(self) -> u64 {
self.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 super::Network;
use super::{Network, ServiceFlags};
use consensus::encode::{deserialize, serialize};
#[test]
@ -133,16 +253,43 @@ mod tests {
);
}
#[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");
#[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");
assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Bitcoin);
assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet);
assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest);
assert!("fakenet".parse::<Network>().is_err());
}
assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Bitcoin);
assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet);
assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest);
assert!("fakenet".parse::<Network>().is_err());
}
#[test]
fn service_flags_test() {
let all = [
ServiceFlags::NETWORK,
ServiceFlags::GETUTXO,
ServiceFlags::BLOOM,
ServiceFlags::WITNESS,
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);
}
}