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

            
17
use scale_info::TypeInfo;
18
use sp_runtime::{
19
	codec::{Decode, Encode},
20
	RuntimeDebug,
21
};
22
use sp_std::vec::Vec;
23

            
24
40
#[derive(Decode, Encode, RuntimeDebug, TypeInfo)]
25
pub struct CurrentOrbiter<AccountId> {
26
	pub account_id: AccountId,
27
	pub removed: bool,
28
}
29
impl<AccountId: Clone> Clone for CurrentOrbiter<AccountId> {
30
2
	fn clone(&self) -> Self {
31
2
		Self {
32
2
			account_id: self.account_id.clone(),
33
2
			removed: self.removed,
34
2
		}
35
2
	}
36
}
37

            
38
pub(super) enum RemoveOrbiterResult {
39
	OrbiterNotFound,
40
	OrbiterRemoved,
41
	OrbiterRemoveScheduled,
42
}
43

            
44
#[derive(Decode, Encode, RuntimeDebug, TypeInfo)]
45
pub(super) struct RotateOrbiterResult<AccountId> {
46
	pub maybe_old_orbiter: Option<CurrentOrbiter<AccountId>>,
47
	pub maybe_next_orbiter: Option<AccountId>,
48
}
49

            
50
60
#[derive(Decode, Encode, RuntimeDebug, TypeInfo)]
51
pub struct CollatorPoolInfo<AccountId> {
52
	orbiters: Vec<AccountId>,
53
	maybe_current_orbiter: Option<CurrentOrbiter<AccountId>>,
54
	next_orbiter: u32,
55
}
56

            
57
impl<AccountId> Default for CollatorPoolInfo<AccountId> {
58
6
	fn default() -> Self {
59
6
		Self {
60
6
			orbiters: Vec::new(),
61
6
			maybe_current_orbiter: None,
62
6
			next_orbiter: 0,
63
6
		}
64
6
	}
65
}
66

            
67
impl<AccountId: Clone + PartialEq> CollatorPoolInfo<AccountId> {
68
7
	pub(super) fn add_orbiter(&mut self, orbiter: AccountId) {
69
7
		if self.next_orbiter > self.orbiters.len() as u32 {
70
1
			self.next_orbiter = 0;
71
6
		}
72
7
		self.orbiters.insert(self.next_orbiter as usize, orbiter);
73
7
		self.next_orbiter += 1;
74
7
	}
75
1
	pub(super) fn contains_orbiter(&self, orbiter: &AccountId) -> bool {
76
1
		if let Some(CurrentOrbiter { ref account_id, .. }) = self.maybe_current_orbiter {
77
			if account_id == orbiter {
78
				return true;
79
			}
80
1
		}
81
1
		for orbiter_ in self.orbiters.iter() {
82
			if orbiter_ == orbiter {
83
				return true;
84
			}
85
		}
86
1
		false
87
1
	}
88
10
	pub(super) fn get_orbiters(&self) -> &[AccountId] {
89
10
		&self.orbiters
90
10
	}
91
4
	pub(super) fn remove_orbiter(&mut self, orbiter: &AccountId) -> RemoveOrbiterResult {
92
4
		let mut found = false;
93
4
		for (index, orbiter_) in self.orbiters.iter().enumerate() {
94
3
			if orbiter_ == orbiter {
95
2
				self.orbiters.remove(index);
96
2
				found = true;
97
2
				break;
98
1
			}
99
		}
100

            
101
4
		if found {
102
			if let Some(CurrentOrbiter {
103
				account_id: ref current_orbiter,
104
				ref mut removed,
105
2
			}) = self.maybe_current_orbiter
106
			{
107
				if current_orbiter == orbiter {
108
					*removed = true;
109
					return RemoveOrbiterResult::OrbiterRemoveScheduled;
110
				}
111
2
			}
112
2
			RemoveOrbiterResult::OrbiterRemoved
113
		} else {
114
2
			RemoveOrbiterResult::OrbiterNotFound
115
		}
116
4
	}
117
3
	pub(super) fn rotate_orbiter(&mut self) -> RotateOrbiterResult<AccountId> {
118
3
		let maybe_old_orbiter = self.maybe_current_orbiter.clone();
119
3
		if self.next_orbiter >= self.orbiters.len() as u32 {
120
2
			self.next_orbiter = 0;
121
2
		}
122
3
		let maybe_next_orbiter =
123
3
			if let Some(next_orbiter) = self.orbiters.get(self.next_orbiter as usize) {
124
3
				self.maybe_current_orbiter = Some(CurrentOrbiter {
125
3
					account_id: next_orbiter.clone(),
126
3
					removed: false,
127
3
				});
128
3
				self.next_orbiter += 1;
129
3
				Some(next_orbiter.clone())
130
			} else {
131
				None
132
			};
133

            
134
3
		RotateOrbiterResult {
135
3
			maybe_old_orbiter,
136
3
			maybe_next_orbiter,
137
3
		}
138
3
	}
139
}
140

            
141
#[derive(Decode, Encode, RuntimeDebug, TypeInfo)]
142
pub struct RoundAuthors<AccountId> {
143
	data: Vec<(AccountId, u32)>,
144
	blocks_count: u32,
145
}
146

            
147
impl<AccountId> Default for RoundAuthors<AccountId> {
148
	fn default() -> Self {
149
		Self {
150
			data: Vec::new(),
151
			blocks_count: 0,
152
		}
153
	}
154
}
155

            
156
impl<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
}