2022-06-29 04:05:31 +00:00
|
|
|
// Written in 2014 by Andrew Poelstra <apoelstra@wpsoftware.net>
|
|
|
|
// SPDX-License-Identifier: CC0-1.0
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2021-11-05 21:58:18 +00:00
|
|
|
//! Bitcoin network constants.
|
2014-07-18 13:56:17 +00:00
|
|
|
//!
|
|
|
|
//! This module provides various constants relating to the Bitcoin network
|
|
|
|
//! protocol, such as protocol versioning and magic header bytes.
|
|
|
|
//!
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
//! The [`Network`][1] type implements the [`Decodable`][2] and
|
|
|
|
//! [`Encodable`][3] traits and encodes the magic bytes of the given
|
2021-11-05 21:58:18 +00:00
|
|
|
//! network.
|
2018-08-10 17:09:22 +00:00
|
|
|
//!
|
|
|
|
//! [1]: enum.Network.html
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
//! [2]: ../../consensus/encode/trait.Decodable.html
|
|
|
|
//! [3]: ../../consensus/encode/trait.Encodable.html
|
2018-08-10 17:09:22 +00:00
|
|
|
//!
|
|
|
|
//! # Example: encoding a network's magic bytes
|
|
|
|
//!
|
|
|
|
//! ```rust
|
|
|
|
//! use bitcoin::network::constants::Network;
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
//! use bitcoin::consensus::encode::serialize;
|
2018-08-10 17:09:22 +00:00
|
|
|
//!
|
|
|
|
//! let network = Network::Bitcoin;
|
2019-05-23 20:28:10 +00:00
|
|
|
//! let bytes = serialize(&network.magic());
|
2018-08-10 17:09:22 +00:00
|
|
|
//!
|
|
|
|
//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]);
|
|
|
|
//! ```
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2022-09-28 00:32:47 +00:00
|
|
|
use core::{fmt, ops, convert::TryFrom, borrow::Borrow, borrow::BorrowMut};
|
2022-09-20 05:27:25 +00:00
|
|
|
use core::str::FromStr;
|
|
|
|
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
use serde::{Deserialize, Serialize};
|
2019-11-22 00:42:15 +00:00
|
|
|
|
2022-05-02 22:13:57 +00:00
|
|
|
use crate::io;
|
2022-09-28 00:32:47 +00:00
|
|
|
use crate::prelude::{String, ToOwned};
|
2022-05-02 22:13:57 +00:00
|
|
|
use crate::consensus::encode::{self, Encodable, Decodable};
|
2022-09-28 00:32:47 +00:00
|
|
|
use crate::internal_macros::debug_from_display;
|
|
|
|
use crate::hashes::hex::{FromHex, Error};
|
2019-11-22 00:42:15 +00:00
|
|
|
|
2018-08-10 17:09:22 +00:00
|
|
|
/// Version of the protocol as appearing in network message headers
|
2020-07-22 22:00:04 +00:00
|
|
|
/// This constant is used to signal to other peers which features you support.
|
|
|
|
/// Increasing it implies that your software also supports every feature prior to this version.
|
|
|
|
/// Doing so without support may lead to you incorrectly banning other peers or other peers banning you.
|
|
|
|
/// These are the features required for each version:
|
|
|
|
/// 70016 - Support receiving `wtxidrelay` message between `version` and `verack` message
|
|
|
|
/// 70015 - Support receiving invalid compact blocks from a peer without banning them
|
|
|
|
/// 70014 - Support compact block messages `sendcmpct`, `cmpctblock`, `getblocktxn` and `blocktxn`
|
|
|
|
/// 70013 - Support `feefilter` message
|
|
|
|
/// 70012 - Support `sendheaders` message and announce new blocks via headers rather than inv
|
|
|
|
/// 70011 - Support NODE_BLOOM service flag and don't support bloom filter messages if it is not set
|
|
|
|
/// 70002 - Support `reject` message
|
|
|
|
/// 70001 - Support bloom filter messages `filterload`, `filterclear` `filteradd`, `merkleblock` and FILTERED_BLOCK inventory type
|
|
|
|
/// 60002 - Support `mempool` message
|
|
|
|
/// 60001 - Support `pong` message and nonce in `ping` message
|
2018-08-10 17:09:22 +00:00
|
|
|
pub const PROTOCOL_VERSION: u32 = 70001;
|
|
|
|
|
2022-09-20 05:27:25 +00:00
|
|
|
/// The cryptocurrency network to act on.
|
|
|
|
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)]
|
|
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
|
|
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
|
|
|
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub enum Network {
|
|
|
|
/// Mainnet Bitcoin.
|
|
|
|
Bitcoin,
|
|
|
|
/// Bitcoin's testnet network.
|
|
|
|
Testnet,
|
|
|
|
/// Bitcoin's signet network.
|
|
|
|
Signet,
|
|
|
|
/// Bitcoin's regtest network.
|
|
|
|
Regtest,
|
2015-01-18 18:16:01 +00:00
|
|
|
}
|
2014-08-03 13:03:00 +00:00
|
|
|
|
2018-08-10 17:09:22 +00:00
|
|
|
impl Network {
|
|
|
|
/// Creates a `Network` from the magic bytes.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
2022-09-28 00:32:47 +00:00
|
|
|
/// use bitcoin::network::constants::{Network, Magic};
|
|
|
|
/// use std::convert::TryFrom;
|
2018-08-10 17:09:22 +00:00
|
|
|
///
|
2022-09-28 00:32:47 +00:00
|
|
|
/// assert_eq!(Ok(Network::Bitcoin), Network::try_from(Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9])));
|
|
|
|
/// assert_eq!(None, Network::from_magic(Magic::from_bytes([0xFF, 0xFF, 0xFF, 0xFF])));
|
2018-08-10 17:09:22 +00:00
|
|
|
/// ```
|
2022-09-28 00:32:47 +00:00
|
|
|
pub fn from_magic(magic: Magic) -> Option<Network> {
|
|
|
|
Network::try_from(magic).ok()
|
2018-08-10 17:09:22 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2018-08-10 17:09:22 +00:00
|
|
|
/// Return the network magic bytes, which should be encoded little-endian
|
|
|
|
/// at the start of every message
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
2022-09-28 00:32:47 +00:00
|
|
|
/// use bitcoin::network::constants::{Network, Magic};
|
2018-08-10 17:09:22 +00:00
|
|
|
///
|
|
|
|
/// let network = Network::Bitcoin;
|
2022-09-28 00:32:47 +00:00
|
|
|
/// assert_eq!(network.magic(), Magic::from_bytes([0xF9, 0xBE, 0xB4, 0xD9]));
|
2018-08-10 17:09:22 +00:00
|
|
|
/// ```
|
2022-09-28 00:32:47 +00:00
|
|
|
pub fn magic(self) -> Magic {
|
|
|
|
Magic::from(self)
|
2022-09-20 05:27:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for Network {
|
|
|
|
type Err = io::Error;
|
|
|
|
#[inline]
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
use Network::*;
|
|
|
|
|
|
|
|
let network = match s {
|
|
|
|
"bitcoin" => Bitcoin,
|
|
|
|
"testnet" => Testnet,
|
|
|
|
"signet" => Signet,
|
|
|
|
"regtest" => Regtest,
|
|
|
|
_ => {
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
let message = format!("Unknown network (type {})", s);
|
|
|
|
#[cfg(not(feature = "std"))]
|
|
|
|
let message = "Unknown network";
|
|
|
|
return Err(io::Error::new(io::ErrorKind::InvalidInput, message));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Ok(network)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-28 00:32:47 +00:00
|
|
|
impl fmt::Display for Network {
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
use Network::*;
|
|
|
|
|
|
|
|
let s = match *self {
|
|
|
|
Bitcoin => "bitcoin",
|
|
|
|
Testnet => "testnet",
|
|
|
|
Signet => "signet",
|
|
|
|
Regtest => "regtest",
|
|
|
|
};
|
|
|
|
write!(f, "{}", s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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]);
|
|
|
|
|
|
|
|
impl Magic {
|
|
|
|
/// Bitcoin mainnet network magic bytes.
|
|
|
|
pub const BITCOIN: Self = Self([0xF9, 0xBE, 0xB4, 0xD9]);
|
|
|
|
/// Bitcoin testnet network magic bytes.
|
|
|
|
pub const TESTNET: Self = Self([0x0B, 0x11, 0x09, 0x07]);
|
|
|
|
/// Bitcoin signet network magic bytes.
|
|
|
|
pub const SIGNET: Self = Self([0x0A, 0x03, 0xCF, 0x40]);
|
|
|
|
/// Bitcoin regtest network magic bytes.
|
|
|
|
pub const REGTEST: Self = Self([0xFA, 0xBF, 0xB5, 0xDA]);
|
|
|
|
|
|
|
|
/// Create network magic from bytes.
|
|
|
|
pub fn from_bytes(bytes: [u8; 4]) -> Magic {
|
|
|
|
Magic(bytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get network magic bytes.
|
|
|
|
pub fn to_bytes(self) -> [u8; 4] {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An error in parsing magic bytes.
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
|
|
pub struct ParseMagicError {
|
|
|
|
/// The error that occurred when parsing the string.
|
|
|
|
error: Error,
|
|
|
|
/// The byte string that failed to parse.
|
|
|
|
magic: String
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
// Note: new network entries must explicitly be matched in `try_from` below.
|
|
|
|
Network::Bitcoin => Magic::BITCOIN,
|
|
|
|
Network::Testnet => Magic::TESTNET,
|
|
|
|
Network::Signet => Magic::SIGNET,
|
|
|
|
Network::Regtest => Magic::REGTEST
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Error in parsing magic from string.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub struct UnknownMagic(Magic);
|
|
|
|
|
|
|
|
impl TryFrom<Magic> for Network {
|
|
|
|
type Error = UnknownMagic;
|
|
|
|
|
|
|
|
fn try_from(magic: Magic) -> Result<Self, Self::Error> {
|
|
|
|
match magic {
|
|
|
|
// Note: any new network entries must be matched against here.
|
|
|
|
Magic::BITCOIN => Ok(Network::Bitcoin),
|
|
|
|
Magic::TESTNET => Ok(Network::Testnet),
|
|
|
|
Magic::SIGNET => Ok(Network::Signet),
|
|
|
|
Magic::REGTEST => Ok(Network::Regtest),
|
|
|
|
_ => Err(UnknownMagic(magic))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Magic {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
bitcoin_internals::fmt_hex_exact!(f, 4, &self.0, bitcoin_internals::hex::Case::Lower)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
debug_from_display!(Magic);
|
|
|
|
|
|
|
|
impl fmt::LowerHex for Magic {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
bitcoin_internals::fmt_hex_exact!(f, 4, &self.0, bitcoin_internals::hex::Case::Lower)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::UpperHex for Magic {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
bitcoin_internals::fmt_hex_exact!(f, 4, &self.0, bitcoin_internals::hex::Case::Upper)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Encodable for Magic {
|
|
|
|
fn consensus_encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
|
|
|
self.0.consensus_encode(writer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Decodable for Magic {
|
|
|
|
fn consensus_decode<R: io::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 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-22 00:42:15 +00:00
|
|
|
/// 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);
|
2022-01-24 00:24:32 +00:00
|
|
|
|
2019-12-21 01:39:30 +00:00
|
|
|
/// 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);
|
2019-11-22 00:42:15 +00:00
|
|
|
|
|
|
|
/// 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);
|
|
|
|
|
2019-12-05 20:13:45 +00:00
|
|
|
// NOTE: When adding new flags, remember to update the Display impl accordingly.
|
|
|
|
|
2019-11-22 00:42:15 +00:00
|
|
|
/// 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.
|
2019-08-05 18:52:34 +00:00
|
|
|
pub fn has(self, flags: ServiceFlags) -> bool {
|
2019-11-22 00:42:15 +00:00
|
|
|
(self.0 | flags.0) == self.0
|
|
|
|
}
|
|
|
|
|
2022-01-19 03:05:01 +00:00
|
|
|
/// Gets the integer representation of this [`ServiceFlags`].
|
|
|
|
pub fn to_u64(self) -> u64 {
|
2019-11-22 00:42:15 +00:00
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-05 20:13:45 +00:00
|
|
|
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 {
|
2019-08-05 18:52:34 +00:00
|
|
|
let mut flags = *self;
|
|
|
|
if flags == ServiceFlags::NONE {
|
2019-12-05 20:13:45 +00:00
|
|
|
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);
|
2019-12-21 02:06:03 +00:00
|
|
|
write_flag!(COMPACT_FILTERS);
|
2019-12-05 20:13:45 +00:00
|
|
|
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, ")")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-22 00:42:15 +00:00
|
|
|
impl From<u64> for ServiceFlags {
|
|
|
|
fn from(f: u64) -> Self {
|
|
|
|
ServiceFlags(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-25 03:19:17 +00:00
|
|
|
impl From<ServiceFlags> for u64 {
|
|
|
|
fn from(flags: ServiceFlags) -> Self {
|
|
|
|
flags.0
|
2019-11-22 00:42:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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]
|
2022-06-29 01:22:12 +00:00
|
|
|
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
Take Writer/Reader by `&mut` in consensus en/decoding
Fix #1020 (see more relevant discussion there)
This definitely makes the amount of generics compiler
has to generate by avoding generating the same functions
for `R`, &mut R`, `&mut &mut R` and so on.
old:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9947832 Jun 2 22:42 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4463024 Jun 2 22:46 target/release/deps/bitcoin-07a9dabf1f3e0266
```
new:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9866800 Jun 2 22:44 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4393392 Jun 2 22:45 target/release/deps/bitcoin-07a9dabf1f3e0266
```
In the unit-test binary itself, it saves ~100KB of data.
I did not expect much performance gains, but turn out I was wrong(*):
old:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,072,710 ns/iter (+/- 21,871)
test blockdata::block::benches::bench_block_serialize ... bench: 191,223 ns/iter (+/- 5,833)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 37,543 ns/iter (+/- 732)
test blockdata::block::benches::bench_stream_reader ... bench: 1,872,455 ns/iter (+/- 149,519)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 136 ns/iter (+/- 3)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 51 ns/iter (+/- 8)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 3 ns/iter (+/- 0)
```
new:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,028,574 ns/iter (+/- 10,910)
test blockdata::block::benches::bench_block_serialize ... bench: 162,143 ns/iter (+/- 3,363)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 30,725 ns/iter (+/- 695)
test blockdata::block::benches::bench_stream_reader ... bench: 1,437,071 ns/iter (+/- 53,694)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 92 ns/iter (+/- 2)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 17 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 4 ns/iter (+/- 0)
```
(*) - I'm benchmarking on a noisy laptop. Take this with a grain of salt. But I think
at least it doesn't make anything slower.
While doing all this manual labor that will probably generate conflicts,
I took a liberty of changing generic type names and variable names to
`r` and `R` (reader) and `w` and `W` for writer.
2022-06-03 04:50:42 +00:00
|
|
|
self.0.consensus_encode(w)
|
2019-11-22 00:42:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Decodable for ServiceFlags {
|
|
|
|
#[inline]
|
2022-06-29 01:22:12 +00:00
|
|
|
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
Take Writer/Reader by `&mut` in consensus en/decoding
Fix #1020 (see more relevant discussion there)
This definitely makes the amount of generics compiler
has to generate by avoding generating the same functions
for `R`, &mut R`, `&mut &mut R` and so on.
old:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9947832 Jun 2 22:42 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4463024 Jun 2 22:46 target/release/deps/bitcoin-07a9dabf1f3e0266
```
new:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9866800 Jun 2 22:44 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4393392 Jun 2 22:45 target/release/deps/bitcoin-07a9dabf1f3e0266
```
In the unit-test binary itself, it saves ~100KB of data.
I did not expect much performance gains, but turn out I was wrong(*):
old:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,072,710 ns/iter (+/- 21,871)
test blockdata::block::benches::bench_block_serialize ... bench: 191,223 ns/iter (+/- 5,833)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 37,543 ns/iter (+/- 732)
test blockdata::block::benches::bench_stream_reader ... bench: 1,872,455 ns/iter (+/- 149,519)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 136 ns/iter (+/- 3)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 51 ns/iter (+/- 8)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 3 ns/iter (+/- 0)
```
new:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,028,574 ns/iter (+/- 10,910)
test blockdata::block::benches::bench_block_serialize ... bench: 162,143 ns/iter (+/- 3,363)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 30,725 ns/iter (+/- 695)
test blockdata::block::benches::bench_stream_reader ... bench: 1,437,071 ns/iter (+/- 53,694)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 92 ns/iter (+/- 2)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 17 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 4 ns/iter (+/- 0)
```
(*) - I'm benchmarking on a noisy laptop. Take this with a grain of salt. But I think
at least it doesn't make anything slower.
While doing all this manual labor that will probably generate conflicts,
I took a liberty of changing generic type names and variable names to
`r` and `R` (reader) and `w` and `W` for writer.
2022-06-03 04:50:42 +00:00
|
|
|
Ok(ServiceFlags(Decodable::consensus_decode(r)?))
|
2019-11-22 00:42:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-03 13:03:00 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-09-28 00:32:47 +00:00
|
|
|
use super::{Network, ServiceFlags, Magic};
|
2022-05-02 22:13:57 +00:00
|
|
|
use crate::consensus::encode::{deserialize, serialize};
|
2022-09-28 00:32:47 +00:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
use std::str::FromStr;
|
2014-08-03 13:03:00 +00:00
|
|
|
|
2019-05-23 20:28:10 +00:00
|
|
|
#[test]
|
|
|
|
fn serialize_test() {
|
2022-01-24 00:31:39 +00:00
|
|
|
assert_eq!(serialize(&Network::Bitcoin.magic()), &[0xf9, 0xbe, 0xb4, 0xd9]);
|
|
|
|
assert_eq!(serialize(&Network::Testnet.magic()), &[0x0b, 0x11, 0x09, 0x07]);
|
|
|
|
assert_eq!(serialize(&Network::Signet.magic()), &[0x0a, 0x03, 0xcf, 0x40]);
|
|
|
|
assert_eq!(serialize(&Network::Regtest.magic()), &[0xfa, 0xbf, 0xb5, 0xda]);
|
|
|
|
|
|
|
|
assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.magic()));
|
|
|
|
assert_eq!(deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet.magic()));
|
|
|
|
assert_eq!(deserialize(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.magic()));
|
|
|
|
assert_eq!(deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.magic()));
|
|
|
|
|
2019-05-23 20:28:10 +00:00
|
|
|
}
|
2018-05-16 09:22:07 +00:00
|
|
|
|
2019-11-22 00:42:15 +00:00
|
|
|
#[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");
|
2019-07-10 04:53:53 +00:00
|
|
|
assert_eq!(Network::Signet.to_string(), "signet");
|
2019-11-22 00:42:15 +00:00
|
|
|
|
|
|
|
assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Bitcoin);
|
|
|
|
assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet);
|
|
|
|
assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest);
|
2019-07-10 04:53:53 +00:00
|
|
|
assert_eq!("signet".parse::<Network>().unwrap(), Network::Signet);
|
2019-11-22 00:42:15 +00:00
|
|
|
assert!("fakenet".parse::<Network>().is_err());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn service_flags_test() {
|
|
|
|
let all = [
|
|
|
|
ServiceFlags::NETWORK,
|
|
|
|
ServiceFlags::GETUTXO,
|
|
|
|
ServiceFlags::BLOOM,
|
|
|
|
ServiceFlags::WITNESS,
|
2019-12-21 01:39:30 +00:00
|
|
|
ServiceFlags::COMPACT_FILTERS,
|
2019-11-22 00:42:15 +00:00
|
|
|
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);
|
2018-05-16 09:22:07 +00:00
|
|
|
|
2019-11-22 00:42:15 +00:00
|
|
|
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);
|
2022-01-24 00:24:32 +00:00
|
|
|
|
2019-12-21 01:39:30 +00:00
|
|
|
flags2 |= ServiceFlags::COMPACT_FILTERS;
|
|
|
|
flags2 ^= ServiceFlags::GETUTXO;
|
|
|
|
assert_eq!(flags2, ServiceFlags::COMPACT_FILTERS);
|
2019-12-05 20:13:45 +00:00
|
|
|
|
|
|
|
// 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();
|
2019-12-21 02:36:47 +00:00
|
|
|
assert_eq!("ServiceFlags(WITNESS|COMPACT_FILTERS|0xb0)", flag.to_string());
|
2019-11-22 00:42:15 +00:00
|
|
|
}
|
2022-09-20 05:19:47 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[cfg(feature = "serde")]
|
|
|
|
fn serde_roundtrip() {
|
|
|
|
use Network::*;
|
|
|
|
let tests = vec![(Bitcoin, "bitcoin"), (Testnet, "testnet"), (Signet, "signet"), (Regtest, "regtest")];
|
|
|
|
|
|
|
|
for tc in tests {
|
|
|
|
let network = tc.0;
|
|
|
|
|
|
|
|
let want = format!("\"{}\"", tc.1);
|
|
|
|
let got = serde_json::to_string(&tc.0).expect("failed to serialize network");
|
|
|
|
assert_eq!(got, want);
|
|
|
|
|
|
|
|
let back: Network = serde_json::from_str(&got).expect("failed to deserialize network");
|
|
|
|
assert_eq!(back, network);
|
|
|
|
}
|
|
|
|
}
|
2022-09-28 00:32:47 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn magic_from_str() {
|
|
|
|
let known_network_magic_strs = [
|
|
|
|
("f9beb4d9", Network::Bitcoin),
|
|
|
|
("0b110907", Network::Testnet),
|
|
|
|
("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);
|
|
|
|
}
|
|
|
|
}
|
2014-08-03 13:03:00 +00:00
|
|
|
}
|