1#![cfg(feature = "runtime-benchmarks")]
21
22use super::*;
23
24use frame_benchmarking::v2::*;
25use frame_support::{
26 assert_noop, assert_ok,
27 traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable},
28};
29use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin};
30use sp_runtime::{traits::Bounded, BoundedVec};
31
32use crate::Pallet as Democracy;
33
34const REFERENDUM_COUNT_HINT: u32 = 10;
35const SEED: u32 = 0;
36
37fn funded_account<T: Config>(name: &'static str, index: u32) -> T::AccountId {
38 let caller: T::AccountId = account(name, index, SEED);
39 T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value() / 2u32.into());
42 caller
43}
44
45fn make_proposal<T: Config>(n: u32) -> BoundedCallOf<T> {
46 let call: CallOf<T> = frame_system::Call::remark { remark: n.encode() }.into();
47 <T as Config>::Preimages::bound(call).unwrap()
48}
49
50fn add_proposal<T: Config>(n: u32) -> Result<T::Hash, &'static str> {
51 let other = funded_account::<T>("proposer", n);
52 let value = T::MinimumDeposit::get();
53 let proposal = make_proposal::<T>(n);
54 Democracy::<T>::propose(RawOrigin::Signed(other).into(), proposal.clone(), value)?;
55 Ok(proposal.hash())
56}
57
58fn add_referendum<T: Config>(n: u32) -> (ReferendumIndex, T::Hash, T::Hash) {
60 let vote_threshold = VoteThreshold::SimpleMajority;
61 let proposal = make_proposal::<T>(n);
62 let hash = proposal.hash();
63 let index = Democracy::<T>::inject_referendum(
64 T::LaunchPeriod::get(),
65 proposal,
66 vote_threshold,
67 0u32.into(),
68 );
69 let preimage_hash = note_preimage::<T>();
70 MetadataOf::<T>::insert(crate::MetadataOwner::Referendum(index), preimage_hash);
71 (index, hash, preimage_hash)
72}
73
74fn account_vote<T: Config>(b: BalanceOf<T>) -> AccountVote<BalanceOf<T>> {
75 let v = Vote { aye: true, conviction: Conviction::Locked1x };
76
77 AccountVote::Standard { vote: v, balance: b }
78}
79
80fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
81 frame_system::Pallet::<T>::assert_last_event(generic_event.into());
82}
83
84fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
85 frame_system::Pallet::<T>::assert_has_event(generic_event.into());
86}
87
88fn note_preimage<T: Config>() -> T::Hash {
90 use alloc::borrow::Cow;
91 use core::sync::atomic::{AtomicU8, Ordering};
92 static COUNTER: AtomicU8 = AtomicU8::new(0);
94 let data = Cow::from(vec![COUNTER.fetch_add(1, Ordering::Relaxed)]);
95 let hash = <T as Config>::Preimages::note(data).unwrap();
96 hash
97}
98
99#[benchmarks]
100mod benchmarks {
101 use super::*;
102
103 #[benchmark]
104 fn propose() -> Result<(), BenchmarkError> {
105 let p = T::MaxProposals::get();
106
107 for i in 0..(p - 1) {
108 add_proposal::<T>(i)?;
109 }
110
111 let caller = funded_account::<T>("caller", 0);
112 let proposal = make_proposal::<T>(0);
113 let value = T::MinimumDeposit::get();
114 whitelist_account!(caller);
115
116 #[extrinsic_call]
117 _(RawOrigin::Signed(caller), proposal, value);
118
119 assert_eq!(PublicProps::<T>::get().len(), p as usize, "Proposals not created.");
120 Ok(())
121 }
122
123 #[benchmark]
124 fn second() -> Result<(), BenchmarkError> {
125 let caller = funded_account::<T>("caller", 0);
126 add_proposal::<T>(0)?;
127
128 for i in 0..T::MaxDeposits::get() - 2 {
131 let seconder = funded_account::<T>("seconder", i);
132 Democracy::<T>::second(RawOrigin::Signed(seconder).into(), 0)?;
133 }
134
135 let deposits = DepositOf::<T>::get(0).ok_or("Proposal not created")?;
136 assert_eq!(deposits.0.len(), (T::MaxDeposits::get() - 1) as usize, "Seconds not recorded");
137 whitelist_account!(caller);
138
139 #[extrinsic_call]
140 _(RawOrigin::Signed(caller), 0);
141
142 let deposits = DepositOf::<T>::get(0).ok_or("Proposal not created")?;
143 assert_eq!(
144 deposits.0.len(),
145 (T::MaxDeposits::get()) as usize,
146 "`second` benchmark did not work"
147 );
148 Ok(())
149 }
150
151 #[benchmark]
152 fn vote_new() -> Result<(), BenchmarkError> {
153 let caller = funded_account::<T>("caller", 0);
154 let account_vote = account_vote::<T>(100u32.into());
155
156 for i in 0..T::MaxVotes::get() - 1 {
158 let ref_index = add_referendum::<T>(i).0;
159 Democracy::<T>::vote(
160 RawOrigin::Signed(caller.clone()).into(),
161 ref_index,
162 account_vote,
163 )?;
164 }
165 let votes = match VotingOf::<T>::get(&caller) {
166 Voting::Direct { votes, .. } => votes,
167 _ => return Err("Votes are not direct".into()),
168 };
169 assert_eq!(votes.len(), (T::MaxVotes::get() - 1) as usize, "Votes were not recorded.");
170
171 let ref_index = add_referendum::<T>(T::MaxVotes::get() - 1).0;
172 whitelist_account!(caller);
173
174 #[extrinsic_call]
175 vote(RawOrigin::Signed(caller.clone()), ref_index, account_vote);
176
177 let votes = match VotingOf::<T>::get(&caller) {
178 Voting::Direct { votes, .. } => votes,
179 _ => return Err("Votes are not direct".into()),
180 };
181
182 assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was not recorded.");
183 Ok(())
184 }
185
186 #[benchmark]
187 fn vote_existing() -> Result<(), BenchmarkError> {
188 let caller = funded_account::<T>("caller", 0);
189 let account_vote = account_vote::<T>(100u32.into());
190
191 for i in 0..T::MaxVotes::get() {
193 let ref_index = add_referendum::<T>(i).0;
194 Democracy::<T>::vote(
195 RawOrigin::Signed(caller.clone()).into(),
196 ref_index,
197 account_vote,
198 )?;
199 }
200 let votes = match VotingOf::<T>::get(&caller) {
201 Voting::Direct { votes, .. } => votes,
202 _ => return Err("Votes are not direct".into()),
203 };
204 assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Votes were not recorded.");
205
206 let nay = Vote { aye: false, conviction: Conviction::Locked1x };
208 let new_vote = AccountVote::Standard { vote: nay, balance: 1000u32.into() };
209 let ref_index = ReferendumCount::<T>::get() - 1;
210
211 whitelist_account!(caller);
213
214 #[extrinsic_call]
215 vote(RawOrigin::Signed(caller.clone()), ref_index, new_vote);
216
217 let votes = match VotingOf::<T>::get(&caller) {
218 Voting::Direct { votes, .. } => votes,
219 _ => return Err("Votes are not direct".into()),
220 };
221 assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was incorrectly added");
222 let referendum_info =
223 ReferendumInfoOf::<T>::get(ref_index).ok_or("referendum doesn't exist")?;
224 let tally = match referendum_info {
225 ReferendumInfo::Ongoing(r) => r.tally,
226 _ => return Err("referendum not ongoing".into()),
227 };
228 assert_eq!(tally.nays, 1000u32.into(), "changed vote was not recorded");
229 Ok(())
230 }
231
232 #[benchmark]
233 fn emergency_cancel() -> Result<(), BenchmarkError> {
234 let origin = T::CancellationOrigin::try_successful_origin()
235 .map_err(|_| BenchmarkError::Weightless)?;
236 let (ref_index, _, preimage_hash) = add_referendum::<T>(0);
237 assert_ok!(Democracy::<T>::referendum_status(ref_index));
238
239 #[extrinsic_call]
240 _(origin as T::RuntimeOrigin, ref_index);
241 assert_noop!(Democracy::<T>::referendum_status(ref_index), Error::<T>::ReferendumInvalid,);
243 assert_last_event::<T>(
244 crate::Event::MetadataCleared {
245 owner: MetadataOwner::Referendum(ref_index),
246 hash: preimage_hash,
247 }
248 .into(),
249 );
250 Ok(())
251 }
252
253 #[benchmark]
254 fn blacklist() -> Result<(), BenchmarkError> {
255 for i in 0..T::MaxProposals::get() - 1 {
257 add_proposal::<T>(i)?;
258 }
259 let (ref_index, hash, preimage_hash) = add_referendum::<T>(0);
263 assert_ok!(Democracy::<T>::referendum_status(ref_index));
264 assert_ok!(Democracy::<T>::external_propose(
266 T::ExternalOrigin::try_successful_origin()
267 .expect("ExternalOrigin has no successful origin required for the benchmark"),
268 make_proposal::<T>(0)
269 ));
270 let origin =
271 T::BlacklistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
272 #[extrinsic_call]
273 _(origin as T::RuntimeOrigin, hash, Some(ref_index));
274
275 assert_noop!(Democracy::<T>::referendum_status(ref_index), Error::<T>::ReferendumInvalid);
277 assert_has_event::<T>(
278 crate::Event::MetadataCleared {
279 owner: MetadataOwner::Referendum(ref_index),
280 hash: preimage_hash,
281 }
282 .into(),
283 );
284 Ok(())
285 }
286
287 #[benchmark]
289 fn external_propose() -> Result<(), BenchmarkError> {
290 let origin =
291 T::ExternalOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
292 let proposal = make_proposal::<T>(0);
293 let addresses: BoundedVec<_, _> = (0..(T::MaxBlacklisted::get() - 1))
296 .into_iter()
297 .map(|i| account::<T::AccountId>("blacklist", i, SEED))
298 .collect::<Vec<_>>()
299 .try_into()
300 .unwrap();
301 Blacklist::<T>::insert(proposal.hash(), (BlockNumberFor::<T>::zero(), addresses));
302 #[extrinsic_call]
303 _(origin as T::RuntimeOrigin, proposal);
304
305 ensure!(NextExternal::<T>::exists(), "External proposal didn't work");
307 Ok(())
308 }
309
310 #[benchmark]
311 fn external_propose_majority() -> Result<(), BenchmarkError> {
312 let origin = T::ExternalMajorityOrigin::try_successful_origin()
313 .map_err(|_| BenchmarkError::Weightless)?;
314 let proposal = make_proposal::<T>(0);
315 #[extrinsic_call]
316 _(origin as T::RuntimeOrigin, proposal);
317
318 ensure!(NextExternal::<T>::exists(), "External proposal didn't work");
320 Ok(())
321 }
322
323 #[benchmark]
324 fn external_propose_default() -> Result<(), BenchmarkError> {
325 let origin = T::ExternalDefaultOrigin::try_successful_origin()
326 .map_err(|_| BenchmarkError::Weightless)?;
327 let proposal = make_proposal::<T>(0);
328 #[extrinsic_call]
329 _(origin as T::RuntimeOrigin, proposal);
330
331 ensure!(NextExternal::<T>::exists(), "External proposal didn't work");
333 Ok(())
334 }
335
336 #[benchmark]
337 fn fast_track() -> Result<(), BenchmarkError> {
338 let origin_propose = T::ExternalDefaultOrigin::try_successful_origin()
339 .expect("ExternalDefaultOrigin has no successful origin required for the benchmark");
340 let proposal = make_proposal::<T>(0);
341 let proposal_hash = proposal.hash();
342 Democracy::<T>::external_propose_default(origin_propose.clone(), proposal)?;
343 let preimage_hash = note_preimage::<T>();
345 assert_ok!(Democracy::<T>::set_metadata(
346 origin_propose,
347 MetadataOwner::External,
348 Some(preimage_hash)
349 ));
350 let origin_fast_track =
352 T::FastTrackOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
353 let voting_period = T::FastTrackVotingPeriod::get();
354 let delay = 0u32;
355 #[extrinsic_call]
356 _(origin_fast_track as T::RuntimeOrigin, proposal_hash, voting_period, delay.into());
357
358 assert_eq!(ReferendumCount::<T>::get(), 1, "referendum not created");
359 assert_last_event::<T>(
360 crate::Event::MetadataTransferred {
361 prev_owner: MetadataOwner::External,
362 owner: MetadataOwner::Referendum(0),
363 hash: preimage_hash,
364 }
365 .into(),
366 );
367 Ok(())
368 }
369
370 #[benchmark]
371 fn veto_external() -> Result<(), BenchmarkError> {
372 let proposal = make_proposal::<T>(0);
373 let proposal_hash = proposal.hash();
374
375 let origin_propose = T::ExternalDefaultOrigin::try_successful_origin()
376 .expect("ExternalDefaultOrigin has no successful origin required for the benchmark");
377 Democracy::<T>::external_propose_default(origin_propose.clone(), proposal)?;
378
379 let preimage_hash = note_preimage::<T>();
380 assert_ok!(Democracy::<T>::set_metadata(
381 origin_propose,
382 MetadataOwner::External,
383 Some(preimage_hash)
384 ));
385
386 let mut vetoers: BoundedVec<T::AccountId, _> = Default::default();
387 for i in 0..(T::MaxBlacklisted::get() - 1) {
388 vetoers.try_push(account::<T::AccountId>("vetoer", i, SEED)).unwrap();
389 }
390 vetoers.sort();
391 Blacklist::<T>::insert(proposal_hash, (BlockNumberFor::<T>::zero(), vetoers));
392
393 let origin =
394 T::VetoOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
395 ensure!(NextExternal::<T>::get().is_some(), "no external proposal");
396 #[extrinsic_call]
397 _(origin as T::RuntimeOrigin, proposal_hash);
398
399 assert!(NextExternal::<T>::get().is_none());
400 let (_, new_vetoers) = Blacklist::<T>::get(&proposal_hash).ok_or("no blacklist")?;
401 assert_eq!(new_vetoers.len(), T::MaxBlacklisted::get() as usize, "vetoers not added");
402 Ok(())
403 }
404
405 #[benchmark]
406 fn cancel_proposal() -> Result<(), BenchmarkError> {
407 for i in 0..T::MaxProposals::get() {
409 add_proposal::<T>(i)?;
410 }
411 let proposer = funded_account::<T>("proposer", 0);
413 let preimage_hash = note_preimage::<T>();
414 assert_ok!(Democracy::<T>::set_metadata(
415 RawOrigin::Signed(proposer).into(),
416 MetadataOwner::Proposal(0),
417 Some(preimage_hash)
418 ));
419 let cancel_origin = T::CancelProposalOrigin::try_successful_origin()
420 .map_err(|_| BenchmarkError::Weightless)?;
421 #[extrinsic_call]
422 _(cancel_origin as T::RuntimeOrigin, 0);
423
424 assert_last_event::<T>(
425 crate::Event::MetadataCleared {
426 owner: MetadataOwner::Proposal(0),
427 hash: preimage_hash,
428 }
429 .into(),
430 );
431 Ok(())
432 }
433
434 #[benchmark]
435 fn cancel_referendum() -> Result<(), BenchmarkError> {
436 let (ref_index, _, preimage_hash) = add_referendum::<T>(0);
437 #[extrinsic_call]
438 _(RawOrigin::Root, ref_index);
439
440 assert_last_event::<T>(
441 crate::Event::MetadataCleared {
442 owner: MetadataOwner::Referendum(0),
443 hash: preimage_hash,
444 }
445 .into(),
446 );
447 Ok(())
448 }
449
450 #[benchmark(extra)]
451 fn on_initialize_external(r: Linear<0, REFERENDUM_COUNT_HINT>) -> Result<(), BenchmarkError> {
452 for i in 0..r {
453 add_referendum::<T>(i);
454 }
455
456 assert_eq!(ReferendumCount::<T>::get(), r, "referenda not created");
457
458 LastTabledWasExternal::<T>::put(false);
460
461 let origin = T::ExternalMajorityOrigin::try_successful_origin()
462 .map_err(|_| BenchmarkError::Weightless)?;
463 let proposal = make_proposal::<T>(r);
464 let call = Call::<T>::external_propose_majority { proposal };
465 call.dispatch_bypass_filter(origin)?;
466 ensure!(NextExternal::<T>::exists(), "External proposal didn't work");
468
469 let block_number = T::LaunchPeriod::get();
470
471 #[block]
472 {
473 Democracy::<T>::on_initialize(block_number);
474 }
475
476 assert_eq!(ReferendumCount::<T>::get(), r + 1, "referenda not created");
478 ensure!(!NextExternal::<T>::exists(), "External wasn't taken");
479
480 for i in 0..r {
482 if let Some(value) = ReferendumInfoOf::<T>::get(i) {
483 match value {
484 ReferendumInfo::Finished { .. } => (),
485 ReferendumInfo::Ongoing(_) => return Err("Referendum was not finished".into()),
486 }
487 }
488 }
489 Ok(())
490 }
491
492 #[benchmark(extra)]
493 fn on_initialize_public(
494 r: Linear<0, { T::MaxVotes::get() - 1 }>,
495 ) -> Result<(), BenchmarkError> {
496 for i in 0..r {
497 add_referendum::<T>(i);
498 }
499
500 assert_eq!(ReferendumCount::<T>::get(), r, "referenda not created");
501
502 assert!(add_proposal::<T>(r).is_ok(), "proposal not created");
504 LastTabledWasExternal::<T>::put(true);
505
506 let block_number = T::LaunchPeriod::get();
507
508 #[block]
509 {
510 Democracy::<T>::on_initialize(block_number);
511 }
512
513 assert_eq!(ReferendumCount::<T>::get(), r + 1, "proposal not accepted");
515
516 for i in 0..r {
518 if let Some(value) = ReferendumInfoOf::<T>::get(i) {
519 match value {
520 ReferendumInfo::Finished { .. } => (),
521 ReferendumInfo::Ongoing(_) => return Err("Referendum was not finished".into()),
522 }
523 }
524 }
525 Ok(())
526 }
527
528 #[benchmark]
530 fn on_initialize_base(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> {
531 for i in 0..r {
532 add_referendum::<T>(i);
533 }
534
535 for (key, mut info) in ReferendumInfoOf::<T>::iter() {
536 if let ReferendumInfo::Ongoing(ref mut status) = info {
537 status.end += 100u32.into();
538 }
539 ReferendumInfoOf::<T>::insert(key, info);
540 }
541
542 assert_eq!(ReferendumCount::<T>::get(), r, "referenda not created");
543 assert_eq!(LowestUnbaked::<T>::get(), 0, "invalid referenda init");
544
545 #[block]
546 {
547 Democracy::<T>::on_initialize(1u32.into());
548 }
549
550 for i in 0..r {
552 if let Some(value) = ReferendumInfoOf::<T>::get(i) {
553 match value {
554 ReferendumInfo::Finished { .. } => {
555 return Err("Referendum has been finished".into())
556 },
557 ReferendumInfo::Ongoing(_) => (),
558 }
559 }
560 }
561 Ok(())
562 }
563
564 #[benchmark]
565 fn on_initialize_base_with_launch_period(
566 r: Linear<0, { T::MaxVotes::get() - 1 }>,
567 ) -> Result<(), BenchmarkError> {
568 for i in 0..r {
569 add_referendum::<T>(i);
570 }
571
572 for (key, mut info) in ReferendumInfoOf::<T>::iter() {
573 if let ReferendumInfo::Ongoing(ref mut status) = info {
574 status.end += 100u32.into();
575 }
576 ReferendumInfoOf::<T>::insert(key, info);
577 }
578
579 assert_eq!(ReferendumCount::<T>::get(), r, "referenda not created");
580 assert_eq!(LowestUnbaked::<T>::get(), 0, "invalid referenda init");
581
582 let block_number = T::LaunchPeriod::get();
583
584 #[block]
585 {
586 Democracy::<T>::on_initialize(block_number);
587 }
588
589 for i in 0..r {
591 if let Some(value) = ReferendumInfoOf::<T>::get(i) {
592 match value {
593 ReferendumInfo::Finished { .. } => {
594 return Err("Referendum has been finished".into())
595 },
596 ReferendumInfo::Ongoing(_) => (),
597 }
598 }
599 }
600 Ok(())
601 }
602
603 #[benchmark]
604 fn delegate(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> {
605 let initial_balance: BalanceOf<T> = 100u32.into();
606 let delegated_balance: BalanceOf<T> = 1000u32.into();
607
608 let caller = funded_account::<T>("caller", 0);
609 let old_delegate: T::AccountId = funded_account::<T>("old_delegate", r);
611 let old_delegate_lookup = T::Lookup::unlookup(old_delegate.clone());
612 Democracy::<T>::delegate(
613 RawOrigin::Signed(caller.clone()).into(),
614 old_delegate_lookup,
615 Conviction::Locked1x,
616 delegated_balance,
617 )?;
618 let (target, balance) = match VotingOf::<T>::get(&caller) {
619 Voting::Delegating { target, balance, .. } => (target, balance),
620 _ => return Err("Votes are not direct".into()),
621 };
622 assert_eq!(target, old_delegate, "delegation target didn't work");
623 assert_eq!(balance, delegated_balance, "delegation balance didn't work");
624 let new_delegate: T::AccountId = funded_account::<T>("new_delegate", r);
626 let new_delegate_lookup = T::Lookup::unlookup(new_delegate.clone());
627 let account_vote = account_vote::<T>(initial_balance);
628 for i in 0..r {
630 let ref_index = add_referendum::<T>(i).0;
631 Democracy::<T>::vote(
632 RawOrigin::Signed(new_delegate.clone()).into(),
633 ref_index,
634 account_vote,
635 )?;
636 }
637 let votes = match VotingOf::<T>::get(&new_delegate) {
638 Voting::Direct { votes, .. } => votes,
639 _ => return Err("Votes are not direct".into()),
640 };
641 assert_eq!(votes.len(), r as usize, "Votes were not recorded.");
642 whitelist_account!(caller);
643
644 #[extrinsic_call]
645 _(
646 RawOrigin::Signed(caller.clone()),
647 new_delegate_lookup,
648 Conviction::Locked1x,
649 delegated_balance,
650 );
651
652 let (target, balance) = match VotingOf::<T>::get(&caller) {
653 Voting::Delegating { target, balance, .. } => (target, balance),
654 _ => return Err("Votes are not direct".into()),
655 };
656 assert_eq!(target, new_delegate, "delegation target didn't work");
657 assert_eq!(balance, delegated_balance, "delegation balance didn't work");
658 let delegations = match VotingOf::<T>::get(&new_delegate) {
659 Voting::Direct { delegations, .. } => delegations,
660 _ => return Err("Votes are not direct".into()),
661 };
662 assert_eq!(delegations.capital, delegated_balance, "delegation was not recorded.");
663 Ok(())
664 }
665
666 #[benchmark]
667 fn undelegate(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> {
668 let initial_balance: BalanceOf<T> = 100u32.into();
669 let delegated_balance: BalanceOf<T> = 1000u32.into();
670
671 let caller = funded_account::<T>("caller", 0);
672 let the_delegate: T::AccountId = funded_account::<T>("delegate", r);
674 let the_delegate_lookup = T::Lookup::unlookup(the_delegate.clone());
675 Democracy::<T>::delegate(
676 RawOrigin::Signed(caller.clone()).into(),
677 the_delegate_lookup,
678 Conviction::Locked1x,
679 delegated_balance,
680 )?;
681 let (target, balance) = match VotingOf::<T>::get(&caller) {
682 Voting::Delegating { target, balance, .. } => (target, balance),
683 _ => return Err("Votes are not direct".into()),
684 };
685 assert_eq!(target, the_delegate, "delegation target didn't work");
686 assert_eq!(balance, delegated_balance, "delegation balance didn't work");
687 let account_vote = account_vote::<T>(initial_balance);
689 for i in 0..r {
690 let ref_index = add_referendum::<T>(i).0;
691 Democracy::<T>::vote(
692 RawOrigin::Signed(the_delegate.clone()).into(),
693 ref_index,
694 account_vote,
695 )?;
696 }
697 let votes = match VotingOf::<T>::get(&the_delegate) {
698 Voting::Direct { votes, .. } => votes,
699 _ => return Err("Votes are not direct".into()),
700 };
701 assert_eq!(votes.len(), r as usize, "Votes were not recorded.");
702 whitelist_account!(caller);
703
704 #[extrinsic_call]
705 _(RawOrigin::Signed(caller.clone()));
706
707 match VotingOf::<T>::get(&caller) {
709 Voting::Direct { .. } => (),
710 _ => return Err("undelegation failed".into()),
711 }
712 Ok(())
713 }
714
715 #[benchmark]
716 fn clear_public_proposals() -> Result<(), BenchmarkError> {
717 add_proposal::<T>(0)?;
718
719 #[extrinsic_call]
720 _(RawOrigin::Root);
721
722 Ok(())
723 }
724
725 #[benchmark]
727 fn unlock_remove(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> {
728 let locker = funded_account::<T>("locker", 0);
729 let locker_lookup = T::Lookup::unlookup(locker.clone());
730 let base_balance: BalanceOf<T> = 100u32.into();
732 let small_vote = account_vote::<T>(base_balance);
733 for i in 0..r {
735 let ref_index = add_referendum::<T>(i).0;
736 Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?;
737 Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?;
738 }
739
740 let caller = funded_account::<T>("caller", 0);
741 whitelist_account!(caller);
742
743 #[extrinsic_call]
744 unlock(RawOrigin::Signed(caller), locker_lookup);
745
746 let voting = VotingOf::<T>::get(&locker);
748 assert_eq!(voting.locked_balance(), BalanceOf::<T>::zero());
749 Ok(())
750 }
751
752 #[benchmark]
754 fn unlock_set(r: Linear<0, { T::MaxVotes::get() - 1 }>) -> Result<(), BenchmarkError> {
755 let locker = funded_account::<T>("locker", 0);
756 let locker_lookup = T::Lookup::unlookup(locker.clone());
757 let base_balance: BalanceOf<T> = 100u32.into();
759 let small_vote = account_vote::<T>(base_balance);
760 for i in 0..r {
761 let ref_index = add_referendum::<T>(i).0;
762 Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?;
763 }
764
765 let big_vote = account_vote::<T>(base_balance * 10u32.into());
767 let ref_index = add_referendum::<T>(r).0;
768 Democracy::<T>::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, big_vote)?;
769
770 let votes = match VotingOf::<T>::get(&locker) {
771 Voting::Direct { votes, .. } => votes,
772 _ => return Err("Votes are not direct".into()),
773 };
774 assert_eq!(votes.len(), (r + 1) as usize, "Votes were not recorded.");
775
776 let voting = VotingOf::<T>::get(&locker);
777 assert_eq!(voting.locked_balance(), base_balance * 10u32.into());
778
779 Democracy::<T>::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?;
780
781 let caller = funded_account::<T>("caller", 0);
782 whitelist_account!(caller);
783
784 #[extrinsic_call]
785 unlock(RawOrigin::Signed(caller), locker_lookup);
786
787 let votes = match VotingOf::<T>::get(&locker) {
788 Voting::Direct { votes, .. } => votes,
789 _ => return Err("Votes are not direct".into()),
790 };
791 assert_eq!(votes.len(), r as usize, "Vote was not removed");
792
793 let voting = VotingOf::<T>::get(&locker);
794 assert_eq!(voting.locked_balance(), if r > 0 { base_balance } else { 0u32.into() });
796 Ok(())
797 }
798
799 #[benchmark]
800 fn remove_vote(r: Linear<1, { T::MaxVotes::get() }>) -> Result<(), BenchmarkError> {
801 let caller = funded_account::<T>("caller", 0);
802 let account_vote = account_vote::<T>(100u32.into());
803
804 for i in 0..r {
805 let ref_index = add_referendum::<T>(i).0;
806 Democracy::<T>::vote(
807 RawOrigin::Signed(caller.clone()).into(),
808 ref_index,
809 account_vote,
810 )?;
811 }
812
813 let votes = match VotingOf::<T>::get(&caller) {
814 Voting::Direct { votes, .. } => votes,
815 _ => return Err("Votes are not direct".into()),
816 };
817 assert_eq!(votes.len(), r as usize, "Votes not created");
818
819 let ref_index = r - 1;
820 whitelist_account!(caller);
821
822 #[extrinsic_call]
823 _(RawOrigin::Signed(caller.clone()), ref_index);
824
825 let votes = match VotingOf::<T>::get(&caller) {
826 Voting::Direct { votes, .. } => votes,
827 _ => return Err("Votes are not direct".into()),
828 };
829 assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed");
830 Ok(())
831 }
832
833 #[benchmark]
835 fn remove_other_vote(r: Linear<1, { T::MaxVotes::get() }>) -> Result<(), BenchmarkError> {
836 let caller = funded_account::<T>("caller", r);
837 let caller_lookup = T::Lookup::unlookup(caller.clone());
838 let account_vote = account_vote::<T>(100u32.into());
839
840 for i in 0..r {
841 let ref_index = add_referendum::<T>(i).0;
842 Democracy::<T>::vote(
843 RawOrigin::Signed(caller.clone()).into(),
844 ref_index,
845 account_vote,
846 )?;
847 }
848
849 let votes = match VotingOf::<T>::get(&caller) {
850 Voting::Direct { votes, .. } => votes,
851 _ => return Err("Votes are not direct".into()),
852 };
853 assert_eq!(votes.len(), r as usize, "Votes not created");
854
855 let ref_index = r - 1;
856 whitelist_account!(caller);
857
858 #[extrinsic_call]
859 _(RawOrigin::Signed(caller.clone()), caller_lookup, ref_index);
860
861 let votes = match VotingOf::<T>::get(&caller) {
862 Voting::Direct { votes, .. } => votes,
863 _ => return Err("Votes are not direct".into()),
864 };
865 assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed");
866 Ok(())
867 }
868
869 #[benchmark]
870 fn set_external_metadata() -> Result<(), BenchmarkError> {
871 let origin = T::ExternalOrigin::try_successful_origin()
872 .expect("ExternalOrigin has no successful origin required for the benchmark");
873 assert_ok!(Democracy::<T>::external_propose(origin.clone(), make_proposal::<T>(0)));
874 let owner = MetadataOwner::External;
875 let hash = note_preimage::<T>();
876
877 #[extrinsic_call]
878 set_metadata(origin as T::RuntimeOrigin, owner.clone(), Some(hash));
879
880 assert_last_event::<T>(crate::Event::MetadataSet { owner, hash }.into());
881 Ok(())
882 }
883
884 #[benchmark]
885 fn clear_external_metadata() -> Result<(), BenchmarkError> {
886 let origin = T::ExternalOrigin::try_successful_origin()
887 .expect("ExternalOrigin has no successful origin required for the benchmark");
888 assert_ok!(Democracy::<T>::external_propose(origin.clone(), make_proposal::<T>(0)));
889 let owner = MetadataOwner::External;
890 let _proposer = funded_account::<T>("proposer", 0);
891 let hash = note_preimage::<T>();
892 assert_ok!(Democracy::<T>::set_metadata(origin.clone(), owner.clone(), Some(hash)));
893
894 #[extrinsic_call]
895 set_metadata(origin as T::RuntimeOrigin, owner.clone(), None);
896
897 assert_last_event::<T>(crate::Event::MetadataCleared { owner, hash }.into());
898 Ok(())
899 }
900
901 #[benchmark]
902 fn set_proposal_metadata() -> Result<(), BenchmarkError> {
903 for i in 0..T::MaxProposals::get() {
905 add_proposal::<T>(i)?;
906 }
907 let owner = MetadataOwner::Proposal(0);
908 let proposer = funded_account::<T>("proposer", 0);
909 let hash = note_preimage::<T>();
910
911 #[extrinsic_call]
912 set_metadata(RawOrigin::Signed(proposer), owner.clone(), Some(hash));
913
914 assert_last_event::<T>(crate::Event::MetadataSet { owner, hash }.into());
915 Ok(())
916 }
917
918 #[benchmark]
919 fn clear_proposal_metadata() -> Result<(), BenchmarkError> {
920 for i in 0..T::MaxProposals::get() {
922 add_proposal::<T>(i)?;
923 }
924 let proposer = funded_account::<T>("proposer", 0);
925 let owner = MetadataOwner::Proposal(0);
926 let hash = note_preimage::<T>();
927 assert_ok!(Democracy::<T>::set_metadata(
928 RawOrigin::Signed(proposer.clone()).into(),
929 owner.clone(),
930 Some(hash)
931 ));
932
933 #[extrinsic_call]
934 set_metadata::<T::RuntimeOrigin>(RawOrigin::Signed(proposer), owner.clone(), None);
935
936 assert_last_event::<T>(crate::Event::MetadataCleared { owner, hash }.into());
937 Ok(())
938 }
939
940 #[benchmark]
941 fn set_referendum_metadata() -> Result<(), BenchmarkError> {
942 ReferendumInfoOf::<T>::insert(
944 0,
945 ReferendumInfo::Finished { end: BlockNumberFor::<T>::zero(), approved: true },
946 );
947 let owner = MetadataOwner::Referendum(0);
948 let _caller = funded_account::<T>("caller", 0);
949 let hash = note_preimage::<T>();
950
951 #[extrinsic_call]
952 set_metadata::<T::RuntimeOrigin>(RawOrigin::Root, owner.clone(), Some(hash));
953
954 assert_last_event::<T>(crate::Event::MetadataSet { owner, hash }.into());
955 Ok(())
956 }
957
958 #[benchmark]
959 fn clear_referendum_metadata() -> Result<(), BenchmarkError> {
960 ReferendumInfoOf::<T>::insert(
962 0,
963 ReferendumInfo::Finished { end: BlockNumberFor::<T>::zero(), approved: true },
964 );
965 let owner = MetadataOwner::Referendum(0);
966 let hash = note_preimage::<T>();
967 MetadataOf::<T>::insert(owner.clone(), hash);
968 let caller = funded_account::<T>("caller", 0);
969
970 #[extrinsic_call]
971 set_metadata::<T::RuntimeOrigin>(RawOrigin::Signed(caller), owner.clone(), None);
972
973 assert_last_event::<T>(crate::Event::MetadataCleared { owner, hash }.into());
974 Ok(())
975 }
976
977 impl_benchmark_test_suite!(Democracy, crate::tests::new_test_ext(), crate::tests::Test);
978}