referrerpolicy=no-referrer-when-downgrade

polkadot_collator_protocol/validator_side_experimental/
common.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17use std::num::NonZeroU16;
18
19use polkadot_node_network_protocol::peer_set::CollationVersion;
20use polkadot_primitives::Id as ParaId;
21
22/// Maximum reputation score.
23pub const MAX_SCORE: u16 = 5000;
24
25/// Limit for the total number connected peers.
26pub const CONNECTED_PEERS_LIMIT: NonZeroU16 = NonZeroU16::new(300).expect("300 is greater than 0");
27
28/// Limit for the total number of connected peers for a paraid.
29/// Must be smaller than `CONNECTED_PEERS_LIMIT`.
30pub const CONNECTED_PEERS_PARA_LIMIT: NonZeroU16 = const {
31	assert!(CONNECTED_PEERS_LIMIT.get() >= 100);
32	NonZeroU16::new(100).expect("100 is greater than 0")
33};
34
35/// Maximum number of relay parents to process for reputation bumps on startup and between finality
36/// notifications.
37pub const MAX_STARTUP_ANCESTRY_LOOKBACK: u32 = 20;
38
39/// Reputation bump for getting a valid candidate included.
40pub const VALID_INCLUDED_CANDIDATE_BUMP: u16 = 50;
41
42/// Reputation slash for peer inactivity (for each included candidate of the para that was not
43/// authored by the peer)
44pub const INACTIVITY_DECAY: u16 = 1;
45
46/// Maximum number of stored peer scores for a paraid. Should be greater than
47/// `CONNECTED_PEERS_PARA_LIMIT`.
48pub const MAX_STORED_SCORES_PER_PARA: u8 = 150;
49/// Reputation score type.
50#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy, Default)]
51pub struct Score(u16);
52
53impl Score {
54	/// Create a new instance. Fail if over the `MAX_SCORE`.
55	pub const fn new(val: u16) -> Option<Self> {
56		if val > MAX_SCORE {
57			None
58		} else {
59			Some(Self(val))
60		}
61	}
62
63	/// Add `val` to the inner value, saturating at `MAX_SCORE`.
64	pub fn saturating_add(&mut self, val: u16) {
65		if (self.0 + val) <= MAX_SCORE {
66			self.0 += val;
67		} else {
68			self.0 = MAX_SCORE;
69		}
70	}
71
72	/// Subtract `val` from the inner value, saturating at 0.
73	pub fn saturating_sub(&mut self, val: u16) {
74		self.0 = self.0.saturating_sub(val);
75	}
76}
77
78impl From<Score> for u16 {
79	fn from(value: Score) -> Self {
80		value.0
81	}
82}
83
84/// Information about a connected peer.
85#[derive(PartialEq, Debug, Clone)]
86pub struct PeerInfo {
87	/// Protocol version.
88	pub version: CollationVersion,
89	/// State of the peer.
90	pub state: PeerState,
91}
92
93/// State of a connected peer
94#[derive(PartialEq, Debug, Clone)]
95pub enum PeerState {
96	/// Connected.
97	Connected,
98	/// Peer has declared.
99	Collating(ParaId),
100}
101
102#[cfg(test)]
103mod tests {
104	use super::*;
105
106	// Test that the `Score` functions are working correctly.
107	#[test]
108	fn score_functions() {
109		assert!(MAX_SCORE > 50);
110
111		// Test that the constructor returns None for values that exceed the limit.
112		for score in (0..MAX_SCORE).step_by(10) {
113			assert_eq!(u16::from(Score::new(score).unwrap()), score);
114		}
115		assert_eq!(u16::from(Score::new(MAX_SCORE).unwrap()), MAX_SCORE);
116		for score in ((MAX_SCORE + 1)..(MAX_SCORE + 50)).step_by(5) {
117			assert_eq!(Score::new(score), None);
118		}
119
120		// Test saturating arithmetic functions.
121		let score = Score::new(50).unwrap();
122
123		// Test addition with value that does not go over the limit.
124		for other_score in (0..(MAX_SCORE - 50)).step_by(10) {
125			let expected_value = u16::from(score) + other_score;
126
127			let mut score = score;
128			score.saturating_add(other_score);
129
130			assert_eq!(expected_value, u16::from(score));
131		}
132
133		// Test overflowing addition.
134		for other_score in ((MAX_SCORE - 50)..MAX_SCORE).step_by(10) {
135			let mut score = score;
136			score.saturating_add(other_score);
137
138			assert_eq!(MAX_SCORE, u16::from(score));
139		}
140
141		// Test subtraction with value that does not go under zero.
142		for other_score in (0..50).step_by(10) {
143			let expected_value = u16::from(score) - other_score;
144
145			let mut score = score;
146			score.saturating_sub(other_score);
147
148			assert_eq!(expected_value, u16::from(score));
149		}
150
151		// Test underflowing subtraction.
152		for other_score in (50..100).step_by(10) {
153			let mut score = score;
154			score.saturating_sub(other_score);
155
156			assert_eq!(0, u16::from(score));
157		}
158	}
159}