pallet_moonbeam_orbiters/
types.rs

1// Copyright 2019-2025 PureStake Inc.
2// This file is part of Moonbeam.
3
4// Moonbeam 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// Moonbeam 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 Moonbeam.  If not, see <http://www.gnu.org/licenses/>
16
17use scale_info::TypeInfo;
18use sp_runtime::{
19	codec::{Decode, Encode},
20	RuntimeDebug,
21};
22use sp_std::vec::Vec;
23
24#[derive(Decode, Encode, RuntimeDebug, TypeInfo)]
25pub struct CurrentOrbiter<AccountId> {
26	pub account_id: AccountId,
27	pub removed: bool,
28}
29impl<AccountId: Clone> Clone for CurrentOrbiter<AccountId> {
30	fn clone(&self) -> Self {
31		Self {
32			account_id: self.account_id.clone(),
33			removed: self.removed,
34		}
35	}
36}
37
38pub(super) enum RemoveOrbiterResult {
39	OrbiterNotFound,
40	OrbiterRemoved,
41	OrbiterRemoveScheduled,
42}
43
44#[derive(Decode, Encode, RuntimeDebug, TypeInfo)]
45pub(super) struct RotateOrbiterResult<AccountId> {
46	pub maybe_old_orbiter: Option<CurrentOrbiter<AccountId>>,
47	pub maybe_next_orbiter: Option<AccountId>,
48}
49
50#[derive(Decode, Encode, RuntimeDebug, TypeInfo)]
51pub struct CollatorPoolInfo<AccountId> {
52	orbiters: Vec<AccountId>,
53	maybe_current_orbiter: Option<CurrentOrbiter<AccountId>>,
54	next_orbiter: u32,
55}
56
57impl<AccountId> Default for CollatorPoolInfo<AccountId> {
58	fn default() -> Self {
59		Self {
60			orbiters: Vec::new(),
61			maybe_current_orbiter: None,
62			next_orbiter: 0,
63		}
64	}
65}
66
67impl<AccountId: Clone + PartialEq> CollatorPoolInfo<AccountId> {
68	pub(super) fn add_orbiter(&mut self, orbiter: AccountId) {
69		if self.next_orbiter > self.orbiters.len() as u32 {
70			self.next_orbiter = 0;
71		}
72		self.orbiters.insert(self.next_orbiter as usize, orbiter);
73		self.next_orbiter += 1;
74	}
75	pub(super) fn contains_orbiter(&self, orbiter: &AccountId) -> bool {
76		if let Some(CurrentOrbiter { ref account_id, .. }) = self.maybe_current_orbiter {
77			if account_id == orbiter {
78				return true;
79			}
80		}
81		for orbiter_ in self.orbiters.iter() {
82			if orbiter_ == orbiter {
83				return true;
84			}
85		}
86		false
87	}
88	pub(super) fn get_orbiters(&self) -> &[AccountId] {
89		&self.orbiters
90	}
91	pub(super) fn remove_orbiter(&mut self, orbiter: &AccountId) -> RemoveOrbiterResult {
92		let mut found = false;
93		for (index, orbiter_) in self.orbiters.iter().enumerate() {
94			if orbiter_ == orbiter {
95				self.orbiters.remove(index);
96				found = true;
97				break;
98			}
99		}
100
101		if found {
102			if let Some(CurrentOrbiter {
103				account_id: ref current_orbiter,
104				ref mut removed,
105			}) = self.maybe_current_orbiter
106			{
107				if current_orbiter == orbiter {
108					*removed = true;
109					return RemoveOrbiterResult::OrbiterRemoveScheduled;
110				}
111			}
112			RemoveOrbiterResult::OrbiterRemoved
113		} else {
114			RemoveOrbiterResult::OrbiterNotFound
115		}
116	}
117	pub(super) fn rotate_orbiter(&mut self) -> RotateOrbiterResult<AccountId> {
118		let maybe_old_orbiter = self.maybe_current_orbiter.clone();
119		if self.next_orbiter >= self.orbiters.len() as u32 {
120			self.next_orbiter = 0;
121		}
122		let maybe_next_orbiter =
123			if let Some(next_orbiter) = self.orbiters.get(self.next_orbiter as usize) {
124				self.maybe_current_orbiter = Some(CurrentOrbiter {
125					account_id: next_orbiter.clone(),
126					removed: false,
127				});
128				self.next_orbiter += 1;
129				Some(next_orbiter.clone())
130			} else {
131				None
132			};
133
134		RotateOrbiterResult {
135			maybe_old_orbiter,
136			maybe_next_orbiter,
137		}
138	}
139}
140
141#[derive(Decode, Encode, RuntimeDebug, TypeInfo)]
142pub struct RoundAuthors<AccountId> {
143	data: Vec<(AccountId, u32)>,
144	blocks_count: u32,
145}
146
147impl<AccountId> Default for RoundAuthors<AccountId> {
148	fn default() -> Self {
149		Self {
150			data: Vec::new(),
151			blocks_count: 0,
152		}
153	}
154}
155
156impl<AccountId: Ord> RoundAuthors<AccountId> {
157	pub fn add_author(&mut self, author: AccountId) {
158		match self
159			.data
160			.binary_search_by(|(account, _counter)| account.cmp(&author))
161		{
162			Ok(index) => self.data[index].1 = self.data[index].1.saturating_add(1),
163			Err(index) => self.data.insert(index, (author, 1)),
164		};
165		self.blocks_count += 1;
166	}
167	pub fn into_data(self) -> (Vec<(AccountId, u32)>, u32) {
168		let Self { data, blocks_count } = self;
169		(data, blocks_count)
170	}
171}