1#![cfg(feature = "runtime-benchmarks")]
21
22use super::*;
23use crate::Pallet as CoreFellowship;
24
25use alloc::{boxed::Box, vec};
26use frame_benchmarking::v2::*;
27use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
28use sp_arithmetic::traits::Bounded;
29
30const SEED: u32 = 0;
31
32type BenchResult = Result<(), BenchmarkError>;
33
34#[instance_benchmarks]
35mod benchmarks {
36 use super::*;
37
38 fn ensure_evidence<T: Config<I>, I: 'static>(who: &T::AccountId) -> BenchResult {
39 let evidence = BoundedVec::try_from(vec![0; Evidence::<T, I>::bound()]).unwrap();
40 let wish = Wish::Retention;
41 let origin = RawOrigin::Signed(who.clone()).into();
42 CoreFellowship::<T, I>::submit_evidence(origin, wish, evidence)?;
43 assert!(MemberEvidence::<T, I>::contains_key(who));
44 Ok(())
45 }
46
47 fn make_member<T: Config<I>, I: 'static>(rank: u16) -> Result<T::AccountId, BenchmarkError> {
48 let member = account("member", 0, SEED);
49 T::Members::induct(&member)?;
50 for _ in 0..rank {
51 T::Members::promote(&member)?;
52 }
53 #[allow(deprecated)]
54 CoreFellowship::<T, I>::import(RawOrigin::Signed(member.clone()).into())?;
55 Ok(member)
56 }
57
58 fn set_benchmark_params<T: Config<I>, I: 'static>() -> Result<(), BenchmarkError> {
59 let max_rank = T::MaxRank::get() as usize;
60 let params = ParamsType {
61 active_salary: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
62 passive_salary: BoundedVec::try_from(vec![10u32.into(); max_rank]).unwrap(),
63 demotion_period: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
64 min_promotion_period: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
65 offboard_timeout: 1u32.into(),
66 };
67
68 CoreFellowship::<T, I>::set_params(RawOrigin::Root.into(), Box::new(params))?;
69 Ok(())
70 }
71
72 #[benchmark]
73 fn set_params() -> Result<(), BenchmarkError> {
74 let max_rank = T::MaxRank::get() as usize;
75 let params = ParamsType {
76 active_salary: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
77 passive_salary: BoundedVec::try_from(vec![10u32.into(); max_rank]).unwrap(),
78 demotion_period: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
79 min_promotion_period: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
80 offboard_timeout: 1u32.into(),
81 };
82
83 #[extrinsic_call]
84 _(RawOrigin::Root, Box::new(params.clone()));
85
86 assert_eq!(Params::<T, I>::get(), params);
87 Ok(())
88 }
89
90 #[benchmark]
91 fn set_partial_params() -> Result<(), BenchmarkError> {
92 let max_rank = T::MaxRank::get() as usize;
93
94 let params = ParamsType {
96 active_salary: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
97 passive_salary: BoundedVec::try_from(vec![10u32.into(); max_rank]).unwrap(),
98 demotion_period: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
99 min_promotion_period: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
100 offboard_timeout: 1u32.into(),
101 };
102 CoreFellowship::<T, I>::set_params(RawOrigin::Root.into(), Box::new(params))?;
103
104 let default_params = Params::<T, I>::get();
105 let expected_params = ParamsType {
106 active_salary: default_params.active_salary,
107 passive_salary: BoundedVec::try_from(vec![10u32.into(); max_rank]).unwrap(),
108 demotion_period: default_params.demotion_period,
109 min_promotion_period: BoundedVec::try_from(vec![100u32.into(); max_rank]).unwrap(),
110 offboard_timeout: 1u32.into(),
111 };
112
113 let params_payload = ParamsType {
114 active_salary: BoundedVec::try_from(vec![None; max_rank]).unwrap(),
115 passive_salary: BoundedVec::try_from(vec![Some(10u32.into()); max_rank]).unwrap(),
116 demotion_period: BoundedVec::try_from(vec![None; max_rank]).unwrap(),
117 min_promotion_period: BoundedVec::try_from(vec![Some(100u32.into()); max_rank])
118 .unwrap(),
119 offboard_timeout: None,
120 };
121
122 #[extrinsic_call]
123 _(RawOrigin::Root, Box::new(params_payload.clone()));
124
125 assert_eq!(Params::<T, I>::get(), expected_params);
126 Ok(())
127 }
128
129 #[benchmark]
130 fn bump_offboard() -> Result<(), BenchmarkError> {
131 set_benchmark_params::<T, I>()?;
132
133 let member = make_member::<T, I>(0)?;
134
135 frame_system::Pallet::<T>::set_block_number(BlockNumberFor::<T>::max_value());
137 ensure_evidence::<T, I>(&member)?;
138 assert!(Member::<T, I>::contains_key(&member));
139
140 #[extrinsic_call]
141 CoreFellowship::<T, I>::bump(RawOrigin::Signed(member.clone()), member.clone());
142
143 assert!(!Member::<T, I>::contains_key(&member));
144 assert!(!MemberEvidence::<T, I>::contains_key(&member));
145 Ok(())
146 }
147
148 #[benchmark]
149 fn bump_demote() -> Result<(), BenchmarkError> {
150 set_benchmark_params::<T, I>()?;
151
152 let initial_rank = T::MaxRank::get();
153
154 let member = make_member::<T, I>(initial_rank)?;
155
156 frame_system::Pallet::<T>::set_block_number(BlockNumberFor::<T>::max_value());
158 ensure_evidence::<T, I>(&member)?;
159
160 assert!(Member::<T, I>::contains_key(&member));
161 assert_eq!(T::Members::rank_of(&member), Some(initial_rank));
162
163 #[extrinsic_call]
164 CoreFellowship::<T, I>::bump(RawOrigin::Signed(member.clone()), member.clone());
165
166 assert!(Member::<T, I>::contains_key(&member));
167 assert_eq!(T::Members::rank_of(&member), Some(initial_rank.saturating_sub(1)));
168 assert!(!MemberEvidence::<T, I>::contains_key(&member));
169 Ok(())
170 }
171
172 #[benchmark]
173 fn set_active() -> Result<(), BenchmarkError> {
174 let member = make_member::<T, I>(1)?;
175 assert!(Member::<T, I>::get(&member).unwrap().is_active);
176
177 #[extrinsic_call]
178 _(RawOrigin::Signed(member.clone()), false);
179
180 assert!(!Member::<T, I>::get(&member).unwrap().is_active);
181 Ok(())
182 }
183
184 #[benchmark]
185 fn induct() -> Result<(), BenchmarkError> {
186 let candidate: T::AccountId = account("candidate", 0, SEED);
187
188 #[extrinsic_call]
189 _(RawOrigin::Root, candidate.clone());
190
191 assert_eq!(T::Members::rank_of(&candidate), Some(0));
192 assert!(Member::<T, I>::contains_key(&candidate));
193 Ok(())
194 }
195
196 #[benchmark]
197 fn promote() -> Result<(), BenchmarkError> {
198 let mut params = Params::<T, I>::get();
200 let max_rank = T::MaxRank::get();
201
202 params.min_promotion_period =
204 BoundedVec::try_from(vec![Zero::zero(); max_rank as usize]).unwrap();
205 Params::<T, I>::put(¶ms);
206
207 let current_rank = 0;
209 let member = make_member::<T, I>(current_rank)?;
210
211 let to_rank = (current_rank + 1).min(max_rank); frame_system::Pallet::<T>::set_block_number(BlockNumberFor::<T>::max_value());
216 ensure_evidence::<T, I>(&member)?;
217
218 #[extrinsic_call]
219 _(RawOrigin::Root, member.clone(), to_rank);
220
221 assert_eq!(T::Members::rank_of(&member), Some(to_rank));
223 assert!(!MemberEvidence::<T, I>::contains_key(&member));
224 Ok(())
225 }
226
227 #[benchmark]
229 fn promote_fast(
230 r: Linear<1, { ConvertU16ToU32::<T::MaxRank>::get() }>,
231 ) -> Result<(), BenchmarkError> {
232 let max_rank = T::MaxRank::get();
234 let target_rank = (r as u16).min(max_rank);
235
236 let member = make_member::<T, I>(0)?;
238
239 ensure_evidence::<T, I>(&member)?;
240
241 #[extrinsic_call]
242 _(RawOrigin::Root, member.clone(), target_rank);
243
244 assert_eq!(T::Members::rank_of(&member), Some(target_rank));
245 assert!(!MemberEvidence::<T, I>::contains_key(&member));
246 Ok(())
247 }
248
249 #[benchmark]
250 fn offboard() -> Result<(), BenchmarkError> {
251 let member = make_member::<T, I>(0)?;
252 T::Members::demote(&member)?;
253 ensure_evidence::<T, I>(&member)?;
254
255 assert!(T::Members::rank_of(&member).is_none());
256 assert!(Member::<T, I>::contains_key(&member));
257 assert!(MemberEvidence::<T, I>::contains_key(&member));
258
259 #[extrinsic_call]
260 _(RawOrigin::Signed(member.clone()), member.clone());
261
262 assert!(!Member::<T, I>::contains_key(&member));
263 assert!(!MemberEvidence::<T, I>::contains_key(&member));
264 Ok(())
265 }
266
267 #[benchmark]
268 fn import() -> Result<(), BenchmarkError> {
269 let member = account("member", 0, SEED);
270 T::Members::induct(&member)?;
271 T::Members::promote(&member)?;
272
273 assert!(!Member::<T, I>::contains_key(&member));
274
275 #[extrinsic_call]
276 _(RawOrigin::Signed(member.clone()));
277
278 assert!(Member::<T, I>::contains_key(&member));
279 Ok(())
280 }
281
282 #[benchmark]
283 fn import_member() -> Result<(), BenchmarkError> {
284 let member = account("member", 0, SEED);
285 let sender = account("sender", 0, SEED);
286
287 T::Members::induct(&member)?;
288 T::Members::promote(&member)?;
289
290 assert!(!Member::<T, I>::contains_key(&member));
291
292 #[extrinsic_call]
293 _(RawOrigin::Signed(sender), member.clone());
294
295 assert!(Member::<T, I>::contains_key(&member));
296 Ok(())
297 }
298
299 #[benchmark]
300 fn approve() -> Result<(), BenchmarkError> {
301 let member = make_member::<T, I>(1)?;
302 let then = frame_system::Pallet::<T>::block_number();
303 let now = then.saturating_plus_one();
304 frame_system::Pallet::<T>::set_block_number(now);
305 ensure_evidence::<T, I>(&member)?;
306
307 assert_eq!(Member::<T, I>::get(&member).unwrap().last_proof, then);
308
309 #[extrinsic_call]
310 _(RawOrigin::Root, member.clone(), 1u8.into());
311
312 assert_eq!(Member::<T, I>::get(&member).unwrap().last_proof, now);
313 assert!(!MemberEvidence::<T, I>::contains_key(&member));
314 Ok(())
315 }
316
317 #[benchmark]
318 fn submit_evidence() -> Result<(), BenchmarkError> {
319 let member = make_member::<T, I>(1)?;
320 let evidence = vec![0; Evidence::<T, I>::bound()].try_into().unwrap();
321
322 assert!(!MemberEvidence::<T, I>::contains_key(&member));
323
324 #[extrinsic_call]
325 _(RawOrigin::Signed(member.clone()), Wish::Retention, evidence);
326
327 assert!(MemberEvidence::<T, I>::contains_key(&member));
328 Ok(())
329 }
330
331 impl_benchmark_test_suite! {
332 CoreFellowship,
333 crate::tests::unit::new_test_ext(),
334 crate::tests::unit::Test,
335 }
336}