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