1#![cfg_attr(not(feature = "std"), no_std)]
200
201pub mod bounds;
202pub mod onchain;
203pub mod traits;
204
205extern crate alloc;
206
207use alloc::{boxed::Box, vec::Vec};
208use core::fmt::Debug;
209use frame_support::traits::{Defensive, DefensiveResult};
210use sp_core::ConstU32;
211use sp_runtime::{
212 traits::{Bounded, Saturating, Zero},
213 RuntimeDebug,
214};
215
216pub use bounds::DataProviderBounds;
217pub use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
218pub use frame_election_provider_solution_type::generate_solution_type;
220pub use frame_support::{traits::Get, weights::Weight, BoundedVec, DefaultNoBound};
221use scale_info::TypeInfo;
222pub use sp_arithmetic::PerThing;
224pub use sp_npos_elections::{
225 Assignment, BalancingConfig, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128,
226 Support, Supports, VoteWeight,
227};
228pub use traits::NposSolution;
229
230#[cfg(feature = "try-runtime")]
231use sp_runtime::TryRuntimeError;
232
233#[doc(hidden)]
235pub mod private {
236 pub use alloc::{
237 collections::{btree_map::BTreeMap, btree_set::BTreeSet},
238 vec::Vec,
239 };
240 pub use codec;
241 pub use scale_info;
242 pub use sp_arithmetic;
243
244 pub trait __OrInvalidIndex<T> {
248 fn or_invalid_index(self) -> Result<T, crate::Error>;
249 }
250
251 impl<T> __OrInvalidIndex<T> for Option<T> {
252 fn or_invalid_index(self) -> Result<T, crate::Error> {
253 self.ok_or(crate::Error::SolutionInvalidIndex)
254 }
255 }
256}
257
258use private::__OrInvalidIndex;
259
260pub mod weights;
261pub use weights::WeightInfo;
262
263#[cfg(test)]
264mod mock;
265#[cfg(test)]
266mod tests;
267
268pub type PageIndex = u32;
270
271#[derive(RuntimeDebug, Clone, Default)]
278#[cfg_attr(feature = "std", derive(PartialEq, Eq, Encode, Decode))]
279pub struct IndexAssignment<VoterIndex, TargetIndex, P: PerThing> {
280 pub who: VoterIndex,
282 pub distribution: Vec<(TargetIndex, P)>,
286}
287
288impl<VoterIndex: core::fmt::Debug, TargetIndex: core::fmt::Debug, P: PerThing>
289 IndexAssignment<VoterIndex, TargetIndex, P>
290{
291 pub fn new<AccountId: IdentifierT>(
292 assignment: &Assignment<AccountId, P>,
293 voter_index: impl Fn(&AccountId) -> Option<VoterIndex>,
294 target_index: impl Fn(&AccountId) -> Option<TargetIndex>,
295 ) -> Result<Self, Error> {
296 Ok(Self {
297 who: voter_index(&assignment.who).or_invalid_index()?,
298 distribution: assignment
299 .distribution
300 .iter()
301 .map(|(target, proportion)| Some((target_index(target)?, *proportion)))
302 .collect::<Option<Vec<_>>>()
303 .or_invalid_index()?,
304 })
305 }
306}
307
308pub type IndexAssignmentOf<C> = IndexAssignment<
310 <C as NposSolution>::VoterIndex,
311 <C as NposSolution>::TargetIndex,
312 <C as NposSolution>::Accuracy,
313>;
314
315pub mod data_provider {
317 pub type Result<T> = core::result::Result<T, &'static str>;
319}
320
321pub trait ElectionDataProvider {
323 type AccountId: Encode;
325
326 type BlockNumber;
328
329 type MaxVotesPerVoter: Get<u32>;
331
332 fn electable_targets(
338 bounds: DataProviderBounds,
339 page: PageIndex,
340 ) -> data_provider::Result<Vec<Self::AccountId>>;
341
342 fn electable_targets_stateless(
346 bounds: DataProviderBounds,
347 ) -> data_provider::Result<Vec<Self::AccountId>> {
348 Self::electable_targets(bounds, 0)
349 }
350
351 fn electing_voters(
359 bounds: DataProviderBounds,
360 page: PageIndex,
361 ) -> data_provider::Result<Vec<VoterOf<Self>>>;
362
363 fn electing_voters_stateless(
367 bounds: DataProviderBounds,
368 ) -> data_provider::Result<Vec<VoterOf<Self>>> {
369 Self::electing_voters(bounds, 0)
370 }
371
372 fn desired_targets() -> data_provider::Result<u32>;
383
384 fn next_election_prediction(now: Self::BlockNumber) -> Self::BlockNumber;
391
392 #[cfg(any(feature = "runtime-benchmarks", test))]
395 fn put_snapshot(
396 _voters: Vec<VoterOf<Self>>,
397 _targets: Vec<Self::AccountId>,
398 _target_stake: Option<VoteWeight>,
399 ) {
400 }
401
402 #[cfg(any(feature = "runtime-benchmarks", test))]
406 fn fetch_page(_page: PageIndex) {}
407
408 #[cfg(any(feature = "runtime-benchmarks", test))]
413 fn add_voter(
414 _voter: Self::AccountId,
415 _weight: VoteWeight,
416 _targets: BoundedVec<Self::AccountId, Self::MaxVotesPerVoter>,
417 ) {
418 }
419
420 #[cfg(any(feature = "runtime-benchmarks", test))]
425 fn add_target(_target: Self::AccountId) {}
426
427 #[cfg(any(feature = "runtime-benchmarks", test))]
429 fn clear() {}
430
431 #[cfg(any(feature = "runtime-benchmarks", test))]
433 fn set_desired_targets(_count: u32) {}
434}
435
436pub trait ElectionProvider {
439 type AccountId;
441
442 type BlockNumber;
444
445 type Error: Debug + PartialEq;
447
448 type MaxWinnersPerPage: Get<u32>;
452
453 type MaxBackersPerWinner: Get<u32>;
460
461 type MaxBackersPerWinnerFinal: Get<u32>;
467
468 type Pages: Get<PageIndex>;
470
471 type DataProvider: ElectionDataProvider<
473 AccountId = Self::AccountId,
474 BlockNumber = Self::BlockNumber,
475 >;
476
477 fn elect(page: PageIndex) -> Result<BoundedSupportsOf<Self>, Self::Error>;
484
485 fn msp() -> PageIndex {
487 Self::Pages::get().saturating_sub(1)
488 }
489
490 fn lsp() -> PageIndex {
492 Zero::zero()
493 }
494
495 fn desired_targets_checked() -> data_provider::Result<u32> {
498 Self::DataProvider::desired_targets().and_then(|desired_targets| {
499 if desired_targets <= Self::MaxWinnersPerPage::get() {
500 Ok(desired_targets)
501 } else {
502 Err("desired_targets must not be greater than MaxWinners.")
503 }
504 })
505 }
506
507 fn duration() -> Self::BlockNumber;
511
512 fn duration_with_export() -> Self::BlockNumber
514 where
515 Self::BlockNumber: From<PageIndex> + core::ops::Add<Output = Self::BlockNumber>,
516 {
517 let export: Self::BlockNumber = Self::Pages::get().into();
518 Self::duration() + export
519 }
520
521 fn start() -> Result<(), Self::Error>;
523
524 fn status() -> Result<bool, ()>;
530
531 #[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
534 fn asap() {}
535}
536
537pub trait InstantElectionProvider: ElectionProvider {
544 fn instant_elect(
545 voters: Vec<VoterOf<Self::DataProvider>>,
546 targets: Vec<Self::AccountId>,
547 desired_targets: u32,
548 ) -> Result<BoundedSupportsOf<Self>, Self::Error>;
549
550 fn bother() -> bool;
554}
555
556pub struct NoElection<X>(core::marker::PhantomData<X>);
558
559impl<AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner> ElectionProvider
560 for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner)>
561where
562 DataProvider: ElectionDataProvider<AccountId = AccountId, BlockNumber = BlockNumber>,
563 MaxWinnersPerPage: Get<u32>,
564 MaxBackersPerWinner: Get<u32>,
565 BlockNumber: Zero,
566{
567 type AccountId = AccountId;
568 type BlockNumber = BlockNumber;
569 type Error = &'static str;
570 type Pages = ConstU32<1>;
571 type DataProvider = DataProvider;
572 type MaxWinnersPerPage = MaxWinnersPerPage;
573 type MaxBackersPerWinner = MaxBackersPerWinner;
574 type MaxBackersPerWinnerFinal = MaxBackersPerWinner;
575
576 fn elect(_page: PageIndex) -> Result<BoundedSupportsOf<Self>, Self::Error> {
577 Err("`NoElection` cannot do anything.")
578 }
579
580 fn start() -> Result<(), Self::Error> {
581 Err("`NoElection` cannot do anything.")
582 }
583
584 fn duration() -> Self::BlockNumber {
585 Zero::zero()
586 }
587
588 fn status() -> Result<bool, ()> {
589 Err(())
590 }
591}
592
593impl<AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner>
594 InstantElectionProvider
595 for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner)>
596where
597 DataProvider: ElectionDataProvider<AccountId = AccountId, BlockNumber = BlockNumber>,
598 MaxWinnersPerPage: Get<u32>,
599 MaxBackersPerWinner: Get<u32>,
600 BlockNumber: Zero,
601{
602 fn instant_elect(
603 _: Vec<VoterOf<Self::DataProvider>>,
604 _: Vec<Self::AccountId>,
605 _: u32,
606 ) -> Result<BoundedSupportsOf<Self>, Self::Error> {
607 Err("`NoElection` cannot do anything.")
608 }
609
610 fn bother() -> bool {
611 false
612 }
613}
614
615pub trait SortedListProvider<AccountId> {
625 type Error: core::fmt::Debug;
627
628 type Score: Bounded + Saturating + Zero + Default;
630
631 fn range() -> (Self::Score, Self::Score) {
640 (Self::Score::min_value(), Self::Score::max_value())
641 }
642
643 fn iter() -> Box<dyn Iterator<Item = AccountId>>;
645
646 fn lock();
655
656 fn unlock();
658
659 fn iter_from(start: &AccountId) -> Result<Box<dyn Iterator<Item = AccountId>>, Self::Error>;
663
664 fn count() -> u32;
666
667 fn contains(id: &AccountId) -> bool;
669
670 fn on_insert(id: AccountId, score: Self::Score) -> Result<(), Self::Error>;
674
675 fn on_update(id: &AccountId, score: Self::Score) -> Result<(), Self::Error>;
681
682 fn get_score(id: &AccountId) -> Result<Self::Score, Self::Error>;
684
685 fn on_increase(id: &AccountId, additional: Self::Score) -> Result<(), Self::Error> {
687 let old_score = Self::get_score(id)?;
688 let new_score = old_score.saturating_add(additional);
689 Self::on_update(id, new_score)
690 }
691
692 fn on_decrease(id: &AccountId, decreased: Self::Score) -> Result<(), Self::Error> {
696 let old_score = Self::get_score(id)?;
697 let new_score = old_score.saturating_sub(decreased);
698 if new_score.is_zero() {
699 Self::on_remove(id)
700 } else {
701 Self::on_update(id, new_score)
702 }
703 }
704
705 fn on_remove(id: &AccountId) -> Result<(), Self::Error>;
709
710 fn unsafe_regenerate(
719 all: impl IntoIterator<Item = AccountId>,
720 score_of: Box<dyn Fn(&AccountId) -> Option<Self::Score>>,
721 ) -> u32;
722
723 fn unsafe_clear();
730
731 #[cfg(feature = "try-runtime")]
733 fn try_state() -> Result<(), TryRuntimeError>;
734
735 #[cfg(feature = "runtime-benchmarks")]
738 fn score_update_worst_case(_who: &AccountId, _is_increase: bool) -> Self::Score;
739}
740
741pub trait ScoreProvider<AccountId> {
745 type Score;
746
747 fn score(who: &AccountId) -> Option<Self::Score>;
751
752 #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", feature = "std"))]
754 fn set_score_of(_: &AccountId, _: Self::Score) {}
755}
756
757pub trait NposSolver {
759 type AccountId: sp_npos_elections::IdentifierT;
761 type Accuracy: PerThing128;
763 type Error: core::fmt::Debug + core::cmp::PartialEq;
765
766 fn solve(
769 to_elect: usize,
770 targets: Vec<Self::AccountId>,
771 voters: Vec<(
772 Self::AccountId,
773 VoteWeight,
774 impl Clone + IntoIterator<Item = Self::AccountId>,
775 )>,
776 ) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error>;
777
778 fn weight<T: WeightInfo>(voters: u32, targets: u32, vote_degree: u32) -> Weight;
783}
784
785pub struct QuickDirtySolver<AccountId, Accuracy>(core::marker::PhantomData<(AccountId, Accuracy)>);
794impl<AccountId: IdentifierT, Accuracy: PerThing128> NposSolver
795 for QuickDirtySolver<AccountId, Accuracy>
796{
797 type AccountId = AccountId;
798 type Accuracy = Accuracy;
799 type Error = &'static str;
800
801 fn solve(
802 to_elect: usize,
803 targets: Vec<Self::AccountId>,
804 voters: Vec<(
805 Self::AccountId,
806 VoteWeight,
807 impl Clone + IntoIterator<Item = Self::AccountId>,
808 )>,
809 ) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error> {
810 use sp_std::collections::btree_map::BTreeMap;
811
812 if to_elect > targets.len() {
813 return Err("to_elect is greater than the number of targets.");
814 }
815
816 let winners = targets.into_iter().take(to_elect).collect::<Vec<_>>();
817
818 let mut assignments = Vec::with_capacity(voters.len());
819 let mut final_winners = BTreeMap::<Self::AccountId, u128>::new();
820
821 for (voter, weight, votes) in voters {
822 let our_winners = winners
823 .iter()
824 .filter(|w| votes.clone().into_iter().any(|v| v == **w))
825 .collect::<Vec<_>>();
826 let our_winners_len = our_winners.len();
827 let distribution = our_winners
828 .into_iter()
829 .map(|w| {
830 *final_winners.entry(w.clone()).or_default() += weight as u128;
831 (w.clone(), Self::Accuracy::from_rational(1, our_winners_len as u128))
832 })
833 .collect::<Vec<_>>();
834
835 let mut assignment = Assignment { who: voter, distribution };
836 assignment.try_normalize().unwrap();
837 assignments.push(assignment);
838 }
839
840 let winners = final_winners.into_iter().collect::<Vec<_>>();
841 Ok(ElectionResult { winners, assignments })
842 }
843
844 fn weight<T: WeightInfo>(_: u32, _: u32, _: u32) -> Weight {
845 Default::default()
846 }
847}
848
849pub struct SequentialPhragmen<AccountId, Accuracy, Balancing = ()>(
852 core::marker::PhantomData<(AccountId, Accuracy, Balancing)>,
853);
854
855impl<AccountId: IdentifierT, Accuracy: PerThing128, Balancing: Get<Option<BalancingConfig>>>
856 NposSolver for SequentialPhragmen<AccountId, Accuracy, Balancing>
857{
858 type AccountId = AccountId;
859 type Accuracy = Accuracy;
860 type Error = sp_npos_elections::Error;
861 fn solve(
862 winners: usize,
863 targets: Vec<Self::AccountId>,
864 voters: Vec<(
865 Self::AccountId,
866 VoteWeight,
867 impl Clone + IntoIterator<Item = Self::AccountId>,
868 )>,
869 ) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error> {
870 sp_npos_elections::seq_phragmen(winners, targets, voters, Balancing::get())
871 }
872
873 fn weight<T: WeightInfo>(voters: u32, targets: u32, vote_degree: u32) -> Weight {
874 T::phragmen(voters, targets, vote_degree)
875 }
876}
877
878pub struct PhragMMS<AccountId, Accuracy, Balancing = ()>(
881 core::marker::PhantomData<(AccountId, Accuracy, Balancing)>,
882);
883
884impl<AccountId: IdentifierT, Accuracy: PerThing128, Balancing: Get<Option<BalancingConfig>>>
885 NposSolver for PhragMMS<AccountId, Accuracy, Balancing>
886{
887 type AccountId = AccountId;
888 type Accuracy = Accuracy;
889 type Error = sp_npos_elections::Error;
890 fn solve(
891 winners: usize,
892 targets: Vec<Self::AccountId>,
893 voters: Vec<(
894 Self::AccountId,
895 VoteWeight,
896 impl Clone + IntoIterator<Item = Self::AccountId>,
897 )>,
898 ) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error> {
899 sp_npos_elections::phragmms(winners, targets, voters, Balancing::get())
900 }
901
902 fn weight<T: WeightInfo>(voters: u32, targets: u32, vote_degree: u32) -> Weight {
903 T::phragmms(voters, targets, vote_degree)
904 }
905}
906
907pub type Voter<AccountId, Bound> = (AccountId, VoteWeight, BoundedVec<AccountId, Bound>);
909
910pub type VoterOf<D> =
912 Voter<<D as ElectionDataProvider>::AccountId, <D as ElectionDataProvider>::MaxVotesPerVoter>;
913
914#[derive(
916 Default, Debug, Encode, Decode, DecodeWithMemTracking, scale_info::TypeInfo, MaxEncodedLen,
917)]
918#[codec(mel_bound(AccountId: MaxEncodedLen, Bound: Get<u32>))]
919#[scale_info(skip_type_params(Bound))]
920pub struct BoundedSupport<AccountId, Bound: Get<u32>> {
921 pub total: ExtendedBalance,
923 pub voters: BoundedVec<(AccountId, ExtendedBalance), Bound>,
925}
926
927impl<AccountId, Bound: Get<u32>> sp_npos_elections::Backings for &BoundedSupport<AccountId, Bound> {
928 fn total(&self) -> ExtendedBalance {
929 self.total
930 }
931}
932
933impl<AccountId: PartialEq, Bound: Get<u32>> PartialEq for BoundedSupport<AccountId, Bound> {
934 fn eq(&self, other: &Self) -> bool {
935 self.total == other.total && self.voters == other.voters
936 }
937}
938
939impl<AccountId, Bound: Get<u32>> From<BoundedSupport<AccountId, Bound>> for Support<AccountId> {
940 fn from(b: BoundedSupport<AccountId, Bound>) -> Self {
941 Support { total: b.total, voters: b.voters.into_inner() }
942 }
943}
944
945impl<AccountId: Clone, Bound: Get<u32>> Clone for BoundedSupport<AccountId, Bound> {
946 fn clone(&self) -> Self {
947 Self { voters: self.voters.clone(), total: self.total }
948 }
949}
950
951impl<AccountId, Bound: Get<u32>> TryFrom<sp_npos_elections::Support<AccountId>>
952 for BoundedSupport<AccountId, Bound>
953{
954 type Error = &'static str;
955 fn try_from(s: sp_npos_elections::Support<AccountId>) -> Result<Self, Self::Error> {
956 let voters = s.voters.try_into().map_err(|_| "voters bound not respected")?;
957 Ok(Self { voters, total: s.total })
958 }
959}
960
961impl<AccountId: Clone, Bound: Get<u32>> BoundedSupport<AccountId, Bound> {
962 pub fn sorted_truncate_from(mut support: sp_npos_elections::Support<AccountId>) -> (Self, u32) {
967 if let Ok(bounded) = support.clone().try_into() {
969 return (bounded, 0)
970 }
971
972 let pre_len = support.voters.len();
973 support.voters.sort_by(|a, b| a.1.cmp(&b.1));
977 let mut bounded = Self { voters: Default::default(), total: 0 };
979 while let Some((voter, weight)) = support.voters.pop() {
980 if let Err(_) = bounded.voters.try_push((voter, weight)) {
981 break
982 }
983 bounded.total += weight;
984 }
985 let post_len = bounded.voters.len();
986 (bounded, (pre_len - post_len) as u32)
987 }
988}
989
990#[derive(Encode, Decode, DecodeWithMemTracking, TypeInfo, DefaultNoBound, MaxEncodedLen)]
998#[codec(mel_bound(AccountId: MaxEncodedLen, BOuter: Get<u32>, BInner: Get<u32>))]
999#[scale_info(skip_type_params(BOuter, BInner))]
1000pub struct BoundedSupports<AccountId, BOuter: Get<u32>, BInner: Get<u32>>(
1001 pub BoundedVec<(AccountId, BoundedSupport<AccountId, BInner>), BOuter>,
1002);
1003
1004pub trait TryFromOtherBounds<AccountId, BOtherOuter: Get<u32>, BOtherInner: Get<u32>> {
1006 fn try_from_other_bounds(
1007 other: BoundedSupports<AccountId, BOtherOuter, BOtherInner>,
1008 ) -> Result<Self, crate::Error>
1009 where
1010 Self: Sized;
1011}
1012
1013impl<
1014 AccountId,
1015 BOuter: Get<u32>,
1016 BInner: Get<u32>,
1017 BOtherOuter: Get<u32>,
1018 BOuterInner: Get<u32>,
1019 > TryFromOtherBounds<AccountId, BOtherOuter, BOuterInner>
1020 for BoundedSupports<AccountId, BOuter, BInner>
1021{
1022 fn try_from_other_bounds(
1023 other: BoundedSupports<AccountId, BOtherOuter, BOuterInner>,
1024 ) -> Result<Self, crate::Error> {
1025 if BOtherOuter::get() <= BOuter::get() && BOuterInner::get() <= BInner::get() {
1027 let supports = other
1029 .into_iter()
1030 .map(|(acc, b_support)| {
1031 b_support
1032 .try_into()
1033 .defensive_map_err(|_| Error::BoundsExceeded)
1034 .map(|b_support| (acc, b_support))
1035 })
1036 .collect::<Result<Vec<_>, _>>()
1037 .defensive()?;
1038 supports.try_into()
1039 } else {
1040 Err(crate::Error::BoundsExceeded)
1041 }
1042 }
1043}
1044
1045impl<AccountId: Clone, BOuter: Get<u32>, BInner: Get<u32>>
1046 BoundedSupports<AccountId, BOuter, BInner>
1047{
1048 pub fn sorted_truncate_from(supports: Supports<AccountId>) -> (Self, u32, u32) {
1053 if let Ok(bounded) = supports.clone().try_into() {
1055 return (bounded, 0, 0)
1056 }
1057
1058 let pre_winners = supports.len();
1059 let mut backers_removed = 0;
1060 let mut inner_supports = supports
1062 .into_iter()
1063 .map(|(account, support)| {
1064 let (bounded, removed) =
1065 BoundedSupport::<AccountId, BInner>::sorted_truncate_from(support);
1066 backers_removed += removed;
1067 (account, bounded)
1068 })
1069 .collect::<Vec<_>>();
1070
1071 inner_supports.sort_by(|a, b| b.1.total.cmp(&a.1.total));
1073
1074 let bounded = BoundedSupports(BoundedVec::<
1076 (AccountId, BoundedSupport<AccountId, BInner>),
1077 BOuter,
1078 >::truncate_from(inner_supports));
1079 let post_winners = bounded.len();
1080 (bounded, (pre_winners - post_winners) as u32, backers_removed)
1081 }
1082}
1083
1084pub trait TryFromUnboundedPagedSupports<AccountId, BOuter: Get<u32>, BInner: Get<u32>> {
1086 fn try_from_unbounded_paged(
1087 self,
1088 ) -> Result<Vec<BoundedSupports<AccountId, BOuter, BInner>>, crate::Error>
1089 where
1090 Self: Sized;
1091}
1092
1093impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>>
1094 TryFromUnboundedPagedSupports<AccountId, BOuter, BInner> for Vec<Supports<AccountId>>
1095{
1096 fn try_from_unbounded_paged(
1097 self,
1098 ) -> Result<Vec<BoundedSupports<AccountId, BOuter, BInner>>, crate::Error> {
1099 self.into_iter()
1100 .map(|s| s.try_into().map_err(|_| crate::Error::BoundsExceeded))
1101 .collect::<Result<Vec<_>, _>>()
1102 }
1103}
1104
1105impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> sp_npos_elections::EvaluateSupport
1106 for BoundedSupports<AccountId, BOuter, BInner>
1107{
1108 fn evaluate(&self) -> sp_npos_elections::ElectionScore {
1109 sp_npos_elections::evaluate_support(self.iter().map(|(_, s)| s))
1110 }
1111}
1112
1113impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> sp_std::ops::DerefMut
1114 for BoundedSupports<AccountId, BOuter, BInner>
1115{
1116 fn deref_mut(&mut self) -> &mut Self::Target {
1117 &mut self.0
1118 }
1119}
1120
1121impl<AccountId: Debug, BOuter: Get<u32>, BInner: Get<u32>> Debug
1122 for BoundedSupports<AccountId, BOuter, BInner>
1123{
1124 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1125 for s in self.0.iter() {
1126 write!(f, "({:?}, {:?}, {:?}) ", s.0, s.1.total, s.1.voters)?;
1127 }
1128 Ok(())
1129 }
1130}
1131
1132impl<AccountId: PartialEq, BOuter: Get<u32>, BInner: Get<u32>> PartialEq
1133 for BoundedSupports<AccountId, BOuter, BInner>
1134{
1135 fn eq(&self, other: &Self) -> bool {
1136 self.0 == other.0
1137 }
1138}
1139
1140impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> Into<Supports<AccountId>>
1141 for BoundedSupports<AccountId, BOuter, BInner>
1142{
1143 fn into(self) -> Supports<AccountId> {
1144 self.0.into_iter().map(|(acc, b_support)| (acc, b_support.into())).collect()
1146 }
1147}
1148
1149impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>>
1150 From<BoundedVec<(AccountId, BoundedSupport<AccountId, BInner>), BOuter>>
1151 for BoundedSupports<AccountId, BOuter, BInner>
1152{
1153 fn from(t: BoundedVec<(AccountId, BoundedSupport<AccountId, BInner>), BOuter>) -> Self {
1154 Self(t)
1155 }
1156}
1157
1158impl<AccountId: Clone, BOuter: Get<u32>, BInner: Get<u32>> Clone
1159 for BoundedSupports<AccountId, BOuter, BInner>
1160{
1161 fn clone(&self) -> Self {
1162 Self(self.0.clone())
1163 }
1164}
1165
1166impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> sp_std::ops::Deref
1167 for BoundedSupports<AccountId, BOuter, BInner>
1168{
1169 type Target = BoundedVec<(AccountId, BoundedSupport<AccountId, BInner>), BOuter>;
1170
1171 fn deref(&self) -> &Self::Target {
1172 &self.0
1173 }
1174}
1175
1176impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> IntoIterator
1177 for BoundedSupports<AccountId, BOuter, BInner>
1178{
1179 type Item = (AccountId, BoundedSupport<AccountId, BInner>);
1180 type IntoIter = sp_std::vec::IntoIter<Self::Item>;
1181
1182 fn into_iter(self) -> Self::IntoIter {
1183 self.0.into_iter()
1184 }
1185}
1186
1187impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> TryFrom<Supports<AccountId>>
1188 for BoundedSupports<AccountId, BOuter, BInner>
1189{
1190 type Error = crate::Error;
1191
1192 fn try_from(supports: Supports<AccountId>) -> Result<Self, Self::Error> {
1193 let mut outer_bounded_supports = BoundedVec::<
1195 (AccountId, BoundedSupport<AccountId, BInner>),
1196 BOuter,
1197 >::with_bounded_capacity(
1198 supports.len().min(BOuter::get() as usize)
1199 );
1200
1201 supports
1203 .into_iter()
1204 .map(|(account, support)| (account, support.try_into().map_err(|_| ())))
1205 .try_for_each(|(account, maybe_bounded_supports)| {
1206 outer_bounded_supports
1207 .try_push((account, maybe_bounded_supports?))
1208 .map_err(|_| ())
1209 })
1210 .map_err(|_| crate::Error::BoundsExceeded)?;
1211
1212 Ok(outer_bounded_supports.into())
1213 }
1214}
1215
1216pub type BoundedSupportsOf<E> = BoundedSupports<
1218 <E as ElectionProvider>::AccountId,
1219 <E as ElectionProvider>::MaxWinnersPerPage,
1220 <E as ElectionProvider>::MaxBackersPerWinner,
1221>;
1222
1223sp_core::generate_feature_enabled_macro!(
1224 runtime_benchmarks_enabled,
1225 feature = "runtime-benchmarks",
1226 $
1227);
1228
1229sp_core::generate_feature_enabled_macro!(
1230 runtime_benchmarks_or_std_enabled,
1231 any(feature = "runtime-benchmarks", feature = "std"),
1232 $
1233);