Move p2p::constants::ServiceFlags to p2p module

The `ServiceFlags` type is used by the p2p layer. It can live in the
`mod.rs` file of the `p2p` module. Done in preparation for removing the
`p2p::constants` module.

This is a straight code move, the `ServiceFlags` replaces the
current re-export.
This commit is contained in:
Tobin C. Harding 2023-05-31 16:41:20 +10:00
parent 99d8ae1173
commit d9d5a4ed4f
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
6 changed files with 210 additions and 159 deletions

View File

@ -6,7 +6,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use std::{env, process};
use bitcoin::consensus::{encode, Decodable};
use bitcoin::p2p::{address, constants, message, message_network};
use bitcoin::p2p::{self, address, constants, message, message_network};
use bitcoin::secp256k1;
use bitcoin::secp256k1::rand::Rng;
@ -75,16 +75,16 @@ fn build_version_message(address: SocketAddr) -> message::NetworkMessage {
let my_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
// "bitfield of features to be enabled for this connection"
let services = constants::ServiceFlags::NONE;
let services = p2p::ServiceFlags::NONE;
// "standard UNIX timestamp in seconds"
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time error").as_secs();
// "The network address of the node receiving this message"
let addr_recv = address::Address::new(&address, constants::ServiceFlags::NONE);
let addr_recv = address::Address::new(&address, p2p::ServiceFlags::NONE);
// "The network address of the node emitting this message"
let addr_from = address::Address::new(&my_address, constants::ServiceFlags::NONE);
let addr_from = address::Address::new(&my_address, p2p::ServiceFlags::NONE);
// "Node random nonce, randomly generated every time a version packet is sent. This nonce is used to detect connections to self."
let nonce: u64 = secp256k1::rand::thread_rng().gen();

View File

@ -11,7 +11,7 @@ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSoc
use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, VarInt, WriteExt};
use crate::io;
use crate::p2p::constants::ServiceFlags;
use crate::p2p::ServiceFlags;
use crate::prelude::*;
/// A message which can be sent on the Bitcoin network
@ -311,7 +311,7 @@ mod test {
use super::{AddrV2, AddrV2Message, Address};
use crate::consensus::encode::{deserialize, serialize};
use crate::internal_macros::hex;
use crate::p2p::constants::ServiceFlags;
use crate::p2p::ServiceFlags;
#[test]
fn serialize_address_test() {

View File

@ -27,9 +27,9 @@
use core::borrow::{Borrow, BorrowMut};
use core::convert::TryFrom;
use core::fmt;
use core::fmt::Display;
use core::str::FromStr;
use core::{fmt, ops};
use hex::FromHex;
use internals::{debug_from_display, write_err};
@ -423,161 +423,14 @@ impl fmt::Display for UnknownMagic {
}
impl_std_error!(UnknownMagic);
/// Flags to indicate which network services a node supports.
#[derive(Debug, Clone, Copy, Default, 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);
/// COMPACT_FILTERS means the node will service basic block filter requests.
/// See BIP157 and BIP158 for details on how this is implemented.
pub const COMPACT_FILTERS: ServiceFlags = ServiceFlags(1 << 6);
/// 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);
// NOTE: When adding new flags, remember to update the Display impl accordingly.
/// 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 }
/// Gets the integer representation of this [`ServiceFlags`].
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);
// If there are unknown flags left, we append them in hex.
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: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
self.0.consensus_encode(w)
}
}
impl Decodable for ServiceFlags {
#[inline]
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(ServiceFlags(Decodable::consensus_decode(r)?))
}
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use std::str::FromStr;
use super::{Magic, Network, ServiceFlags};
use super::{Magic, Network};
use crate::consensus::encode::{deserialize, serialize};
use crate::p2p::ServiceFlags;
#[test]
fn serialize_test() {

View File

@ -550,13 +550,14 @@ mod test {
use crate::consensus::encode::{deserialize, deserialize_partial, serialize};
use crate::internal_macros::hex;
use crate::p2p::address::{AddrV2, AddrV2Message, Address};
use crate::p2p::constants::{Magic, Network, ServiceFlags};
use crate::p2p::constants::{Magic, Network};
use crate::p2p::message_blockdata::{GetBlocksMessage, GetHeadersMessage, Inventory};
use crate::p2p::message_bloom::{BloomFlags, FilterAdd, FilterLoad};
use crate::p2p::message_compact_blocks::{GetBlockTxn, SendCmpct};
use crate::p2p::message_filter::{
CFCheckpt, CFHeaders, CFilter, GetCFCheckpt, GetCFHeaders, GetCFilters,
};
use crate::p2p::ServiceFlags;
fn hash(slice: [u8; 32]) -> Hash { Hash::from_slice(&slice).unwrap() }

View File

@ -11,7 +11,7 @@ use hashes::sha256d;
use crate::consensus::{encode, Decodable, Encodable, ReadExt};
use crate::internal_macros::impl_consensus_encoding;
use crate::p2p::address::Address;
use crate::p2p::constants::ServiceFlags;
use crate::p2p::ServiceFlags;
use crate::prelude::*;
use crate::{io, p2p};
@ -146,7 +146,7 @@ mod tests {
use super::{Reject, RejectReason, VersionMessage};
use crate::consensus::encode::{deserialize, serialize};
use crate::internal_macros::hex;
use crate::p2p::constants::ServiceFlags;
use crate::p2p::ServiceFlags;
#[test]
fn version_message_test() {

View File

@ -24,7 +24,11 @@ pub mod message_filter;
#[cfg(feature = "std")]
pub mod message_network;
use core::{fmt, ops};
pub use self::constants::Magic;
use crate::consensus::encode::{self, Decodable, Encodable};
use crate::io;
/// Version of the protocol as appearing in network message headers.
///
@ -44,3 +48,196 @@ pub use self::constants::Magic;
/// 60002 - Support `mempool` message
/// 60001 - Support `pong` message and nonce in `ping` message
pub const PROTOCOL_VERSION: u32 = 70001;
/// Flags to indicate which network services a node supports.
#[derive(Debug, Clone, Copy, Default, 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);
/// COMPACT_FILTERS means the node will service basic block filter requests.
/// See BIP157 and BIP158 for details on how this is implemented.
pub const COMPACT_FILTERS: ServiceFlags = ServiceFlags(1 << 6);
/// 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);
// NOTE: When adding new flags, remember to update the Display impl accordingly.
/// 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 }
/// Gets the integer representation of this [`ServiceFlags`].
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);
// If there are unknown flags left, we append them in hex.
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: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
self.0.consensus_encode(w)
}
}
impl Decodable for ServiceFlags {
#[inline]
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(ServiceFlags(Decodable::consensus_decode(r)?))
}
}
#[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);
// Test formatting.
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());
}
}