1use core::{fmt, ops, convert::From};
41
42use io;
43use consensus::encode::{self, Encodable, Decodable};
44
45pub const PROTOCOL_VERSION: u32 = 70001;
61
62user_enum! {
63 #[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)]
65 pub enum Network {
66 Bitcoin <-> "bitcoin",
68 Testnet <-> "testnet",
70 Signet <-> "signet",
72 Regtest <-> "regtest"
74 }
75}
76
77impl Network {
78 pub fn from_magic(magic: u32) -> Option<Network> {
89 match magic {
91 0xD9B4BEF9 => Some(Network::Bitcoin),
92 0x0709110B => Some(Network::Testnet),
93 0x40CF030A => Some(Network::Signet),
94 0xDAB5BFFA => Some(Network::Regtest),
95 _ => None
96 }
97 }
98
99 pub fn magic(self) -> u32 {
111 match self {
113 Network::Bitcoin => 0xD9B4BEF9,
114 Network::Testnet => 0x0709110B,
115 Network::Signet => 0x40CF030A,
116 Network::Regtest => 0xDAB5BFFA,
117 }
118 }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
123pub struct ServiceFlags(u64);
124
125impl ServiceFlags {
126 pub const NONE: ServiceFlags = ServiceFlags(0);
128
129 pub const NETWORK: ServiceFlags = ServiceFlags(1 << 0);
133
134 pub const GETUTXO: ServiceFlags = ServiceFlags(1 << 1);
138
139 pub const BLOOM: ServiceFlags = ServiceFlags(1 << 2);
143
144 pub const WITNESS: ServiceFlags = ServiceFlags(1 << 3);
147
148 pub const COMPACT_FILTERS: ServiceFlags = ServiceFlags(1 << 6);
151
152 pub const NETWORK_LIMITED: ServiceFlags = ServiceFlags(1 << 10);
156
157 pub fn add(&mut self, other: ServiceFlags) -> ServiceFlags {
163 self.0 |= other.0;
164 *self
165 }
166
167 pub fn remove(&mut self, other: ServiceFlags) -> ServiceFlags {
171 self.0 ^= other.0;
172 *self
173 }
174
175 pub fn has(self, flags: ServiceFlags) -> bool {
177 (self.0 | flags.0) == self.0
178 }
179
180 pub fn as_u64(self) -> u64 {
182 self.0
183 }
184}
185
186impl fmt::LowerHex for ServiceFlags {
187 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
188 fmt::LowerHex::fmt(&self.0, f)
189 }
190}
191
192impl fmt::UpperHex for ServiceFlags {
193 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194 fmt::UpperHex::fmt(&self.0, f)
195 }
196}
197
198impl fmt::Display for ServiceFlags {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 let mut flags = *self;
201 if flags == ServiceFlags::NONE {
202 return write!(f, "ServiceFlags(NONE)");
203 }
204 let mut first = true;
205 macro_rules! write_flag {
206 ($f:ident) => {
207 if flags.has(ServiceFlags::$f) {
208 if !first {
209 write!(f, "|")?;
210 }
211 first = false;
212 write!(f, stringify!($f))?;
213 flags.remove(ServiceFlags::$f);
214 }
215 }
216 }
217 write!(f, "ServiceFlags(")?;
218 write_flag!(NETWORK);
219 write_flag!(GETUTXO);
220 write_flag!(BLOOM);
221 write_flag!(WITNESS);
222 write_flag!(COMPACT_FILTERS);
223 write_flag!(NETWORK_LIMITED);
224 if flags != ServiceFlags::NONE {
226 if !first {
227 write!(f, "|")?;
228 }
229 write!(f, "0x{:x}", flags)?;
230 }
231 write!(f, ")")
232 }
233}
234
235impl From<u64> for ServiceFlags {
236 fn from(f: u64) -> Self {
237 ServiceFlags(f)
238 }
239}
240
241impl Into<u64> for ServiceFlags {
242 fn into(self) -> u64 {
243 self.0
244 }
245}
246
247impl ops::BitOr for ServiceFlags {
248 type Output = Self;
249
250 fn bitor(mut self, rhs: Self) -> Self {
251 self.add(rhs)
252 }
253}
254
255impl ops::BitOrAssign for ServiceFlags {
256 fn bitor_assign(&mut self, rhs: Self) {
257 self.add(rhs);
258 }
259}
260
261impl ops::BitXor for ServiceFlags {
262 type Output = Self;
263
264 fn bitxor(mut self, rhs: Self) -> Self {
265 self.remove(rhs)
266 }
267}
268
269impl ops::BitXorAssign for ServiceFlags {
270 fn bitxor_assign(&mut self, rhs: Self) {
271 self.remove(rhs);
272 }
273}
274
275impl Encodable for ServiceFlags {
276 #[inline]
277 fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, io::Error> {
278 self.0.consensus_encode(&mut s)
279 }
280}
281
282impl Decodable for ServiceFlags {
283 #[inline]
284 fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
285 Ok(ServiceFlags(Decodable::consensus_decode(&mut d)?))
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::{Network, ServiceFlags};
292 use consensus::encode::{deserialize, serialize};
293
294 #[test]
295 fn serialize_test() {
296 assert_eq!(serialize(&Network::Bitcoin.magic()), &[0xf9, 0xbe, 0xb4, 0xd9]);
297 assert_eq!(serialize(&Network::Testnet.magic()), &[0x0b, 0x11, 0x09, 0x07]);
298 assert_eq!(serialize(&Network::Signet.magic()), &[0x0a, 0x03, 0xcf, 0x40]);
299 assert_eq!(serialize(&Network::Regtest.magic()), &[0xfa, 0xbf, 0xb5, 0xda]);
300
301 assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.magic()));
302 assert_eq!(deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet.magic()));
303 assert_eq!(deserialize(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.magic()));
304 assert_eq!(deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.magic()));
305
306 }
307
308 #[test]
309 fn string_test() {
310 assert_eq!(Network::Bitcoin.to_string(), "bitcoin");
311 assert_eq!(Network::Testnet.to_string(), "testnet");
312 assert_eq!(Network::Regtest.to_string(), "regtest");
313 assert_eq!(Network::Signet.to_string(), "signet");
314
315 assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Bitcoin);
316 assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet);
317 assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest);
318 assert_eq!("signet".parse::<Network>().unwrap(), Network::Signet);
319 assert!("fakenet".parse::<Network>().is_err());
320 }
321
322 #[test]
323 fn service_flags_test() {
324 let all = [
325 ServiceFlags::NETWORK,
326 ServiceFlags::GETUTXO,
327 ServiceFlags::BLOOM,
328 ServiceFlags::WITNESS,
329 ServiceFlags::COMPACT_FILTERS,
330 ServiceFlags::NETWORK_LIMITED,
331 ];
332
333 let mut flags = ServiceFlags::NONE;
334 for f in all.iter() {
335 assert!(!flags.has(*f));
336 }
337
338 flags |= ServiceFlags::WITNESS;
339 assert_eq!(flags, ServiceFlags::WITNESS);
340
341 let mut flags2 = flags | ServiceFlags::GETUTXO;
342 for f in all.iter() {
343 assert_eq!(flags2.has(*f), *f == ServiceFlags::WITNESS || *f == ServiceFlags::GETUTXO);
344 }
345
346 flags2 ^= ServiceFlags::WITNESS;
347 assert_eq!(flags2, ServiceFlags::GETUTXO);
348
349 flags2 |= ServiceFlags::COMPACT_FILTERS;
350 flags2 ^= ServiceFlags::GETUTXO;
351 assert_eq!(flags2, ServiceFlags::COMPACT_FILTERS);
352
353 assert_eq!("ServiceFlags(NONE)", ServiceFlags::NONE.to_string());
355 assert_eq!("ServiceFlags(WITNESS)", ServiceFlags::WITNESS.to_string());
356 let flag = ServiceFlags::WITNESS | ServiceFlags::BLOOM | ServiceFlags::NETWORK;
357 assert_eq!("ServiceFlags(NETWORK|BLOOM|WITNESS)", flag.to_string());
358 let flag = ServiceFlags::WITNESS | 0xf0.into();
359 assert_eq!("ServiceFlags(WITNESS|COMPACT_FILTERS|0xb0)", flag.to_string());
360 }
361}