collectives_westend_runtime/fellowship/origins.rs
1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17//! Fellowship custom origins.
18
19use super::ranks;
20pub use pallet_origins::*;
21
22#[frame_support::pallet]
23pub mod pallet_origins {
24 use super::ranks;
25 use frame_support::pallet_prelude::*;
26 use pallet_ranked_collective::Rank;
27
28 #[pallet::config]
29 pub trait Config: frame_system::Config {}
30
31 #[pallet::pallet]
32 pub struct Pallet<T>(_);
33
34 #[derive(
35 PartialEq,
36 Eq,
37 Clone,
38 MaxEncodedLen,
39 Encode,
40 Decode,
41 DecodeWithMemTracking,
42 TypeInfo,
43 RuntimeDebug,
44 )]
45 #[pallet::origin]
46 pub enum Origin {
47 /// Origin aggregated through weighted votes of those with rank 1 or above; `Success` is 1.
48 /// Aka the "voice" of all Members.
49 Members,
50 /// Origin aggregated through weighted votes of those with rank 2 or above; `Success` is 2.
51 /// Aka the "voice" of members at least II Dan.
52 Fellowship2Dan,
53 /// Origin aggregated through weighted votes of those with rank 3 or above; `Success` is 3.
54 /// Aka the "voice" of all Fellows.
55 Fellows,
56 /// Origin aggregated through weighted votes of those with rank 4 or above; `Success` is 4.
57 /// Aka the "voice" of members at least IV Dan.
58 Architects,
59 /// Origin aggregated through weighted votes of those with rank 5 or above; `Success` is 5.
60 /// Aka the "voice" of members at least V Dan.
61 Fellowship5Dan,
62 /// Origin aggregated through weighted votes of those with rank 6 or above; `Success` is 6.
63 /// Aka the "voice" of members at least VI Dan.
64 Fellowship6Dan,
65 /// Origin aggregated through weighted votes of those with rank 7 or above; `Success` is 7.
66 /// Aka the "voice" of all Masters.
67 Masters,
68 /// Origin aggregated through weighted votes of those with rank 8 or above; `Success` is 8.
69 /// Aka the "voice" of members at least VIII Dan.
70 Fellowship8Dan,
71 /// Origin aggregated through weighted votes of those with rank 9 or above; `Success` is 9.
72 /// Aka the "voice" of members at least IX Dan.
73 Fellowship9Dan,
74
75 /// Origin aggregated through weighted votes of those with rank 3 or above when voting on
76 /// a fortnight-long track; `Success` is 1.
77 RetainAt1Dan,
78 /// Origin aggregated through weighted votes of those with rank 4 or above when voting on
79 /// a fortnight-long track; `Success` is 2.
80 RetainAt2Dan,
81 /// Origin aggregated through weighted votes of those with rank 5 or above when voting on
82 /// a fortnight-long track; `Success` is 3.
83 RetainAt3Dan,
84 /// Origin aggregated through weighted votes of those with rank 6 or above when voting on
85 /// a fortnight-long track; `Success` is 4.
86 RetainAt4Dan,
87 /// Origin aggregated through weighted votes of those with rank 7 or above when voting on
88 /// a fortnight-long track; `Success` is 5.
89 RetainAt5Dan,
90 /// Origin aggregated through weighted votes of those with rank 8 or above when voting on
91 /// a fortnight-long track; `Success` is 6.
92 RetainAt6Dan,
93
94 /// Origin aggregated through weighted votes of those with rank 3 or above when voting on
95 /// a month-long track; `Success` is 1.
96 PromoteTo1Dan,
97 /// Origin aggregated through weighted votes of those with rank 4 or above when voting on
98 /// a month-long track; `Success` is 2.
99 PromoteTo2Dan,
100 /// Origin aggregated through weighted votes of those with rank 5 or above when voting on
101 /// a month-long track; `Success` is 3.
102 PromoteTo3Dan,
103 /// Origin aggregated through weighted votes of those with rank 6 or above when voting on
104 /// a month-long track; `Success` is 4.
105 PromoteTo4Dan,
106 /// Origin aggregated through weighted votes of those with rank 7 or above when voting on
107 /// a month-long track; `Success` is 5.
108 PromoteTo5Dan,
109 /// Origin aggregated through weighted votes of those with rank 8 or above when voting on
110 /// a month-long track; `Success` is 6.
111 PromoteTo6Dan,
112 }
113
114 impl Origin {
115 /// Returns the rank that the origin `self` speaks for, or `None` if it doesn't speak for
116 /// any.
117 ///
118 /// `Some` will be returned only for the first 9 elements of [Origin].
119 pub fn as_voice(&self) -> Option<pallet_ranked_collective::Rank> {
120 Some(match &self {
121 Origin::Members => ranks::DAN_1,
122 Origin::Fellowship2Dan => ranks::DAN_2,
123 Origin::Fellows => ranks::DAN_3,
124 Origin::Architects => ranks::DAN_4,
125 Origin::Fellowship5Dan => ranks::DAN_5,
126 Origin::Fellowship6Dan => ranks::DAN_6,
127 Origin::Masters => ranks::DAN_7,
128 Origin::Fellowship8Dan => ranks::DAN_8,
129 Origin::Fellowship9Dan => ranks::DAN_9,
130 _ => return None,
131 })
132 }
133 }
134
135 /// A `TryMorph` implementation which is designed to convert an aggregate `RuntimeOrigin`
136 /// value into the Fellowship voice it represents if it is a Fellowship pallet origin an
137 /// appropriate variant. See also [Origin::as_voice].
138 pub struct ToVoice;
139 impl<'a, O: 'a + TryInto<&'a Origin>> sp_runtime::traits::TryMorph<O> for ToVoice {
140 type Outcome = pallet_ranked_collective::Rank;
141 fn try_morph(o: O) -> Result<pallet_ranked_collective::Rank, ()> {
142 o.try_into().ok().and_then(Origin::as_voice).ok_or(())
143 }
144 }
145
146 macro_rules! decl_unit_ensures {
147 ( $name:ident: $success_type:ty = $success:expr ) => {
148 pub struct $name;
149 impl<O: OriginTrait + From<Origin>> EnsureOrigin<O> for $name
150 where
151 for <'a> &'a O::PalletsOrigin: TryInto<&'a Origin>,
152 {
153 type Success = $success_type;
154 fn try_origin(o: O) -> Result<Self::Success, O> {
155 match o.caller().try_into() {
156 Ok(Origin::$name) => return Ok($success),
157 _ => (),
158 }
159
160 Err(o)
161 }
162 #[cfg(feature = "runtime-benchmarks")]
163 fn try_successful_origin() -> Result<O, ()> {
164 Ok(O::from(Origin::$name))
165 }
166 }
167 };
168 ( $name:ident ) => { decl_unit_ensures! { $name : () = () } };
169 ( $name:ident: $success_type:ty = $success:expr, $( $rest:tt )* ) => {
170 decl_unit_ensures! { $name: $success_type = $success }
171 decl_unit_ensures! { $( $rest )* }
172 };
173 ( $name:ident, $( $rest:tt )* ) => {
174 decl_unit_ensures! { $name }
175 decl_unit_ensures! { $( $rest )* }
176 };
177 () => {}
178 }
179 decl_unit_ensures!(
180 Members: Rank = ranks::DAN_1,
181 Fellows: Rank = ranks::DAN_3,
182 Architects: Rank = ranks::DAN_4,
183 Masters: Rank = ranks::DAN_7,
184 );
185
186 macro_rules! decl_ensure {
187 (
188 $vis:vis type $name:ident: EnsureOrigin<Success = $success_type:ty> {
189 $( $item:ident = $success:expr, )*
190 }
191 ) => {
192 $vis struct $name;
193 impl<O: OriginTrait + From<Origin>> EnsureOrigin<O> for $name
194 where
195 for <'a> &'a O::PalletsOrigin: TryInto<&'a Origin>,
196 {
197 type Success = $success_type;
198 fn try_origin(o: O) -> Result<Self::Success, O> {
199 match o.caller().try_into() {
200 $(
201 Ok(Origin::$item) => return Ok($success),
202 )*
203 _ => (),
204 }
205
206 Err(o)
207 }
208 #[cfg(feature = "runtime-benchmarks")]
209 fn try_successful_origin() -> Result<O, ()> {
210 // By convention the more privileged origins go later, so for greatest chance
211 // of success, we want the last one.
212 let _result: Result<O, ()> = Err(());
213 $(
214 let _result: Result<O, ()> = Ok(O::from(Origin::$item));
215 )*
216 _result
217 }
218 }
219 }
220 }
221
222 // Fellowship origin indicating weighted voting from at least the rank of `Success` on a
223 // week-long track.
224 decl_ensure! {
225 pub type EnsureFellowship: EnsureOrigin<Success = Rank> {
226 Members = ranks::DAN_1,
227 Fellowship2Dan = ranks::DAN_2,
228 Fellows = ranks::DAN_3,
229 Architects = ranks::DAN_4,
230 Fellowship5Dan = ranks::DAN_5,
231 Fellowship6Dan = ranks::DAN_6,
232 Masters = ranks::DAN_7,
233 Fellowship8Dan = ranks::DAN_8,
234 Fellowship9Dan = ranks::DAN_9,
235 }
236 }
237
238 // Fellowship origin indicating weighted voting from at least the rank of `Success + 2` on
239 // a fortnight-long track; needed for Fellowship retention voting.
240 decl_ensure! {
241 pub type EnsureCanRetainAt: EnsureOrigin<Success = Rank> {
242 RetainAt1Dan = ranks::DAN_1,
243 RetainAt2Dan = ranks::DAN_2,
244 RetainAt3Dan = ranks::DAN_3,
245 RetainAt4Dan = ranks::DAN_4,
246 RetainAt5Dan = ranks::DAN_5,
247 RetainAt6Dan = ranks::DAN_6,
248 }
249 }
250
251 // Fellowship origin indicating weighted voting from at least the rank of `Success + 2` on
252 // a month-long track; needed for Fellowship promotion voting.
253 decl_ensure! {
254 pub type EnsureCanPromoteTo: EnsureOrigin<Success = Rank> {
255 PromoteTo1Dan = ranks::DAN_1,
256 PromoteTo2Dan = ranks::DAN_2,
257 PromoteTo3Dan = ranks::DAN_3,
258 PromoteTo4Dan = ranks::DAN_4,
259 PromoteTo5Dan = ranks::DAN_5,
260 PromoteTo6Dan = ranks::DAN_6,
261 }
262 }
263}