Skip to main content

soil_network/common/
role.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
6
7#![allow(clippy::bad_bit_mask)]
8
9use codec::{self, Encode, EncodeLike, Input, Output};
10
11/// Role that the peer sent to us during the handshake, with the addition of what our local node
12/// knows about that peer.
13///
14/// > **Note**: This enum is different from the `Role` enum. The `Role` enum indicates what a
15/// >			node says about itself, while `ObservedRole` is a `Role` merged with the
16/// >			information known locally about that node.
17#[derive(Debug, Copy, Clone, PartialEq, Eq)]
18pub enum ObservedRole {
19	/// Full node.
20	Full,
21	/// Light node.
22	Light,
23	/// Third-party authority.
24	Authority,
25}
26
27impl ObservedRole {
28	/// Returns `true` for `ObservedRole::Light`.
29	pub fn is_light(&self) -> bool {
30		matches!(self, Self::Light)
31	}
32}
33
34impl From<Roles> for ObservedRole {
35	fn from(roles: Roles) -> Self {
36		if roles.is_authority() {
37			ObservedRole::Authority
38		} else if roles.is_full() {
39			ObservedRole::Full
40		} else {
41			ObservedRole::Light
42		}
43	}
44}
45
46/// Role of the local node.
47#[derive(Debug, Clone, Copy)]
48pub enum Role {
49	/// Regular full node.
50	Full,
51	/// Actual authority.
52	Authority,
53}
54
55impl Role {
56	/// True for [`Role::Authority`].
57	pub fn is_authority(&self) -> bool {
58		matches!(self, Self::Authority)
59	}
60}
61
62impl std::fmt::Display for Role {
63	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64		match self {
65			Self::Full => write!(f, "FULL"),
66			Self::Authority => write!(f, "AUTHORITY"),
67		}
68	}
69}
70
71bitflags::bitflags! {
72	/// Bitmask of the roles that a node fulfills.
73	pub struct Roles: u8 {
74		/// No network.
75		const NONE = 0b00000000;
76		/// Full node, does not participate in consensus.
77		const FULL = 0b00000001;
78		/// Light client node.
79		const LIGHT = 0b00000010;
80		/// Act as an authority
81		const AUTHORITY = 0b00000100;
82	}
83}
84
85impl Roles {
86	/// Does this role represents a client that holds full chain data locally?
87	pub fn is_full(&self) -> bool {
88		self.intersects(Self::FULL | Self::AUTHORITY)
89	}
90
91	/// Does this role represents a client that does not participates in the consensus?
92	pub fn is_authority(&self) -> bool {
93		*self == Self::AUTHORITY
94	}
95
96	/// Does this role represents a client that does not hold full chain data locally?
97	pub fn is_light(&self) -> bool {
98		!self.is_full()
99	}
100}
101
102impl<'a> From<&'a Role> for Roles {
103	fn from(roles: &'a Role) -> Self {
104		match roles {
105			Role::Full => Self::FULL,
106			Role::Authority => Self::AUTHORITY,
107		}
108	}
109}
110
111impl Encode for Roles {
112	fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) {
113		dest.push_byte(self.bits())
114	}
115}
116
117impl EncodeLike for Roles {}
118
119impl codec::Decode for Roles {
120	fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
121		Self::from_bits(input.read_byte()?).ok_or_else(|| codec::Error::from("Invalid bytes"))
122	}
123}