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