1#![cfg_attr(not(feature = "std"), no_std)]
201
202pub mod bounds;
203pub mod onchain;
204pub mod traits;
205
206extern crate alloc;
207
208use alloc::{boxed::Box, vec::Vec};
209use core::fmt::Debug;
210use frame_support::traits::{Defensive, DefensiveResult};
211use sp_core::ConstU32;
212use sp_runtime::traits::{Bounded, Saturating, Zero};
213
214pub use bounds::DataProviderBounds;
215pub use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
216pub use frame_election_provider_solution_type::generate_solution_type;
218pub use frame_support::{traits::Get, weights::Weight, BoundedVec, DefaultNoBound};
219use scale_info::TypeInfo;
220pub use sp_arithmetic::PerThing;
222pub use sp_npos_elections::{
223 Assignment, BalancingConfig, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128,
224 Support, Supports, VoteWeight,
225};
226pub use traits::NposSolution;
227
228#[cfg(feature = "try-runtime")]
229use sp_runtime::TryRuntimeError;
230
231#[doc(hidden)]
233pub mod private {
234 pub use alloc::{
235 collections::{btree_map::BTreeMap, btree_set::BTreeSet},
236 vec::Vec,
237 };
238 pub use codec;
239 pub use scale_info;
240 pub use sp_arithmetic;
241
242 pub trait __OrInvalidIndex<T> {
246 fn or_invalid_index(self) -> Result<T, crate::Error>;
247 }
248
249 impl<T> __OrInvalidIndex<T> for Option<T> {
250 fn or_invalid_index(self) -> Result<T, crate::Error> {
251 self.ok_or(crate::Error::SolutionInvalidIndex)
252 }
253 }
254}
255
256use private::__OrInvalidIndex;
257
258pub mod weights;
259pub use weights::WeightInfo;
260
261#[cfg(test)]
262mod mock;
263#[cfg(test)]
264mod tests;
265
266pub type PageIndex = u32;
268
269#[derive(Debug, Clone, Default)]
276#[cfg_attr(feature = "std", derive(PartialEq, Eq, Encode, Decode))]
277pub struct IndexAssignment<VoterIndex, TargetIndex, P: PerThing> {
278 pub who: VoterIndex,
280 pub distribution: Vec<(TargetIndex, P)>,
284}
285
286impl<VoterIndex: core::fmt::Debug, TargetIndex: core::fmt::Debug, P: PerThing>
287 IndexAssignment<VoterIndex, TargetIndex, P>
288{
289 pub fn new<AccountId: IdentifierT>(
290 assignment: &Assignment<AccountId, P>,
291 voter_index: impl Fn(&AccountId) -> Option<VoterIndex>,
292 target_index: impl Fn(&AccountId) -> Option<TargetIndex>,
293 ) -> Result<Self, Error> {
294 Ok(Self {
295 who: voter_index(&assignment.who).or_invalid_index()?,
296 distribution: assignment
297 .distribution
298 .iter()
299 .map(|(target, proportion)| Some((target_index(target)?, *proportion)))
300 .collect::<Option<Vec<_>>>()
301 .or_invalid_index()?,
302 })
303 }
304}
305
306pub type IndexAssignmentOf<C> = IndexAssignment<
308 <C as NposSolution>::VoterIndex,
309 <C as NposSolution>::TargetIndex,
310 <C as NposSolution>::Accuracy,
311>;
312
313pub mod data_provider {
315 pub type Result<T> = core::result::Result<T, &'static str>;
317}
318
319pub trait ElectionDataProvider {
321 type AccountId: Encode;
323
324 type BlockNumber;
326
327 type MaxVotesPerVoter: Get<u32>;
329
330 fn electable_targets(
336 bounds: DataProviderBounds,
337 page: PageIndex,
338 ) -> data_provider::Result<Vec<Self::AccountId>>;
339
340 fn electable_targets_stateless(
344 bounds: DataProviderBounds,
345 ) -> data_provider::Result<Vec<Self::AccountId>> {
346 Self::electable_targets(bounds, 0)
347 }
348
349 fn electing_voters(
357 bounds: DataProviderBounds,
358 page: PageIndex,
359 ) -> data_provider::Result<Vec<VoterOf<Self>>>;
360
361 fn electing_voters_stateless(
365 bounds: DataProviderBounds,
366 ) -> data_provider::Result<Vec<VoterOf<Self>>> {
367 Self::electing_voters(bounds, 0)
368 }
369
370 fn desired_targets() -> data_provider::Result<u32>;
381
382 fn next_election_prediction(now: Self::BlockNumber) -> Self::BlockNumber;
389
390 #[cfg(any(feature = "runtime-benchmarks", test))]
393 fn put_snapshot(
394 _voters: Vec<VoterOf<Self>>,
395 _targets: Vec<Self::AccountId>,
396 _target_stake: Option<VoteWeight>,
397 ) {
398 }
399
400 #[cfg(any(feature = "runtime-benchmarks", test))]
404 fn fetch_page(_page: PageIndex) {}
405
406 #[cfg(any(feature = "runtime-benchmarks", test))]
411 fn add_voter(
412 _voter: Self::AccountId,
413 _weight: VoteWeight,
414 _targets: BoundedVec<Self::AccountId, Self::MaxVotesPerVoter>,
415 ) {
416 }
417
418 #[cfg(any(feature = "runtime-benchmarks", test))]
423 fn add_target(_target: Self::AccountId) {}
424
425 #[cfg(any(feature = "runtime-benchmarks", test))]
427 fn clear() {}
428
429 #[cfg(any(feature = "runtime-benchmarks", test))]
431 fn set_desired_targets(_count: u32) {}
432}
433
434pub trait ElectionProvider {
437 type AccountId;
439
440 type BlockNumber;
442
443 type Error: Debug + PartialEq;
445
446 type MaxWinnersPerPage: Get<u32>;
450
451 type MaxBackersPerWinner: Get<u32>;
458
459 type MaxBackersPerWinnerFinal: Get<u32>;
465
466 type Pages: Get<PageIndex>;
468
469 type DataProvider: ElectionDataProvider<
471 AccountId = Self::AccountId,
472 BlockNumber = Self::BlockNumber,
473 >;
474
475 fn elect(page: PageIndex) -> Result<BoundedSupportsOf<Self>, Self::Error>;
482
483 fn msp() -> PageIndex {
485 Self::Pages::get().saturating_sub(1)
486 }
487
488 fn lsp() -> PageIndex {
490 Zero::zero()
491 }
492
493 fn desired_targets_checked() -> data_provider::Result<u32> {
496 Self::DataProvider::desired_targets().and_then(|desired_targets| {
497 if desired_targets <= Self::MaxWinnersPerPage::get() {
498 Ok(desired_targets)
499 } else {
500 Err("desired_targets must not be greater than MaxWinners.")
501 }
502 })
503 }
504
505 fn duration() -> Self::BlockNumber;
509
510 fn duration_with_export() -> Self::BlockNumber
512 where
513 Self::BlockNumber: From<PageIndex> + core::ops::Add<Output = Self::BlockNumber>,
514 {
515 let export: Self::BlockNumber = Self::Pages::get().into();
516 Self::duration() + export
517 }
518
519 fn start() -> Result<(), Self::Error>;
521
522 fn status() -> Result<Option<Weight>, ()>;
531
532 #[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
535 fn asap() {}
536}
537
538pub trait InstantElectionProvider: ElectionProvider {
545 fn instant_elect(
546 voters: Vec<VoterOf<Self::DataProvider>>,
547 targets: Vec<Self::AccountId>,
548 desired_targets: u32,
549 ) -> Result<BoundedSupportsOf<Self>, Self::Error>;
550
551 fn bother() -> bool;
555}
556
557pub struct NoElection<X>(core::marker::PhantomData<X>);
559
560impl<AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner> ElectionProvider
561 for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner)>
562where
563 DataProvider: ElectionDataProvider<AccountId = AccountId, BlockNumber = BlockNumber>,
564 MaxWinnersPerPage: Get<u32>,
565 MaxBackersPerWinner: Get<u32>,
566 BlockNumber: Zero,
567{
568 type AccountId = AccountId;
569 type BlockNumber = BlockNumber;
570 type Error = &'static str;
571 type Pages = ConstU32<1>;
572 type DataProvider = DataProvider;
573 type MaxWinnersPerPage = MaxWinnersPerPage;
574 type MaxBackersPerWinner = MaxBackersPerWinner;
575 type MaxBackersPerWinnerFinal = MaxBackersPerWinner;
576
577 fn elect(_page: PageIndex) -> Result<BoundedSupportsOf<Self>, Self::Error> {
578 Err("`NoElection` cannot do anything.")
579 }
580
581 fn start() -> Result<(), Self::Error> {
582 Err("`NoElection` cannot do anything.")
583 }
584
585 fn duration() -> Self::BlockNumber {
586 Zero::zero()
587 }
588
589 fn status() -> Result<Option<Weight>, ()> {
590 Err(())
591 }
592}
593
594impl<AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner>
595 InstantElectionProvider
596 for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner)>
597where
598 DataProvider: ElectionDataProvider<AccountId = AccountId, BlockNumber = BlockNumber>,
599 MaxWinnersPerPage: Get<u32>,
600 MaxBackersPerWinner: Get<u32>,
601 BlockNumber: Zero,
602{
603 fn instant_elect(
604 _: Vec<VoterOf<Self::DataProvider>>,
605 _: Vec<Self::AccountId>,
606 _: u32,
607 ) -> Result<BoundedSupportsOf<Self>, Self::Error> {
608 Err("`NoElection` cannot do anything.")
609 }
610
611 fn bother() -> bool {
612 false
613 }
614}
615
616pub trait SortedListProvider<AccountId> {
626 type Error: core::fmt::Debug;
628
629 type Score: Bounded + Saturating + Zero + Default;
631
632 fn range() -> (Self::Score, Self::Score) {
641 (Self::Score::min_value(), Self::Score::max_value())
642 }
643
644 fn iter() -> Box<dyn Iterator<Item = AccountId>>;
646
647 fn lock();
656
657 fn unlock();
659
660 fn iter_from(start: &AccountId) -> Result<Box<dyn Iterator<Item = AccountId>>, Self::Error>;
664
665 fn count() -> u32;
667
668 fn contains(id: &AccountId) -> bool;
670
671 fn on_insert(id: AccountId, score: Self::Score) -> Result<(), Self::Error>;
675
676 fn on_update(id: &AccountId, score: Self::Score) -> Result<(), Self::Error>;
682
683 fn get_score(id: &AccountId) -> Result<Self::Score, Self::Error>;
685
686 fn on_increase(id: &AccountId, additional: Self::Score) -> Result<(), Self::Error> {
688 let old_score = Self::get_score(id)?;
689 let new_score = old_score.saturating_add(additional);
690 Self::on_update(id, new_score)
691 }
692
693 fn on_decrease(id: &AccountId, decreased: Self::Score) -> Result<(), Self::Error> {
697 let old_score = Self::get_score(id)?;
698 let new_score = old_score.saturating_sub(decreased);
699 if new_score.is_zero() {
700 Self::on_remove(id)
701 } else {
702 Self::on_update(id, new_score)
703 }
704 }
705
706 fn on_remove(id: &AccountId) -> Result<(), Self::Error>;
710
711 fn unsafe_regenerate(
720 all: impl IntoIterator<Item = AccountId>,
721 score_of: Box<dyn Fn(&AccountId) -> Option<Self::Score>>,
722 ) -> u32;
723
724 fn unsafe_clear();
731
732 #[cfg(feature = "try-runtime")]
734 fn try_state() -> Result<(), TryRuntimeError>;
735
736 #[cfg(feature = "runtime-benchmarks")]
739 fn score_update_worst_case(_who: &AccountId, _is_increase: bool) -> Self::Score;
740}
741
742pub trait ScoreProvider<AccountId> {
746 type Score;
747
748 fn score(who: &AccountId) -> Option<Self::Score>;
752
753 #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", feature = "std"))]
755 fn set_score_of(_: &AccountId, _: Self::Score) {}
756}
757
758pub trait NposSolver {
760 type AccountId: sp_npos_elections::IdentifierT;
762 type Accuracy: PerThing128;
764 type Error: core::fmt::Debug + core::cmp::PartialEq;
766
767 fn solve(
770 to_elect: usize,
771 targets: Vec<Self::AccountId>,
772 voters: Vec<(
773 Self::AccountId,
774 VoteWeight,
775 impl Clone + IntoIterator<Item = Self::AccountId>,
776 )>,
777 ) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error>;
778
779 fn weight<T: WeightInfo>(voters: u32, targets: u32, vote_degree: u32) -> Weight;
784}
785
786#[cfg(feature = "runtime-benchmarks")]
795pub struct QuickDirtySolver<AccountId, Accuracy>(core::marker::PhantomData<(AccountId, Accuracy)>);
796#[cfg(feature = "runtime-benchmarks")]
797impl<AccountId: IdentifierT, Accuracy: PerThing128> NposSolver
798 for QuickDirtySolver<AccountId, Accuracy>
799{
800 type AccountId = AccountId;
801 type Accuracy = Accuracy;
802 type Error = &'static str;
803
804 fn solve(
805 to_elect: usize,
806 targets: Vec<Self::AccountId>,
807 voters: Vec<(
808 Self::AccountId,
809 VoteWeight,
810 impl Clone + IntoIterator<Item = Self::AccountId>,
811 )>,
812 ) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error> {
813 use sp_std::collections::btree_map::BTreeMap;
814
815 if to_elect > targets.len() {
816 return Err("to_elect is greater than the number of targets.");
817 }
818
819 let winners = targets.into_iter().take(to_elect).collect::<Vec<_>>();
820
821 let mut assignments = Vec::with_capacity(voters.len());
822 let mut final_winners = BTreeMap::<Self::AccountId, u128>::new();
823
824 for (voter, weight, votes) in voters {
825 let our_winners = winners
827 .iter()
828 .filter(|w| votes.clone().into_iter().any(|v| v == **w))
829 .collect::<Vec<_>>();
830 let our_winners_len = our_winners.len();
831 let distribution = our_winners
833 .into_iter()
834 .map(|w| {
835 *final_winners.entry(w.clone()).or_default() += weight as u128;
836 (w.clone(), Self::Accuracy::from_rational(1, our_winners_len as u128))
837 })
838 .collect::<Vec<_>>();
839
840 let mut assignment = Assignment { who: voter, distribution };
841 assignment.try_normalize().unwrap();
842 assignments.push(assignment);
843 }
844
845 let winners = final_winners.into_iter().collect::<Vec<_>>();
846 Ok(ElectionResult { winners, assignments })
847 }
848
849 fn weight<T: WeightInfo>(_: u32, _: u32, _: u32) -> Weight {
850 Default::default()
851 }
852}
853
854pub struct SequentialPhragmen<AccountId, Accuracy, Balancing = ()>(
857 core::marker::PhantomData<(AccountId, Accuracy, Balancing)>,
858);
859
860impl<AccountId: IdentifierT, Accuracy: PerThing128, Balancing: Get<Option<BalancingConfig>>>
861 NposSolver for SequentialPhragmen<AccountId, Accuracy, Balancing>
862{
863 type AccountId = AccountId;
864 type Accuracy = Accuracy;
865 type Error = sp_npos_elections::Error;
866 fn solve(
867 winners: usize,
868 targets: Vec<Self::AccountId>,
869 voters: Vec<(
870 Self::AccountId,
871 VoteWeight,
872 impl Clone + IntoIterator<Item = Self::AccountId>,
873 )>,
874 ) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error> {
875 sp_npos_elections::seq_phragmen(winners, targets, voters, Balancing::get())
876 }
877
878 fn weight<T: WeightInfo>(voters: u32, targets: u32, vote_degree: u32) -> Weight {
879 T::phragmen(voters, targets, vote_degree)
880 }
881}
882
883pub struct PhragMMS<AccountId, Accuracy, Balancing = ()>(
886 core::marker::PhantomData<(AccountId, Accuracy, Balancing)>,
887);
888
889impl<AccountId: IdentifierT, Accuracy: PerThing128, Balancing: Get<Option<BalancingConfig>>>
890 NposSolver for PhragMMS<AccountId, Accuracy, Balancing>
891{
892 type AccountId = AccountId;
893 type Accuracy = Accuracy;
894 type Error = sp_npos_elections::Error;
895 fn solve(
896 winners: usize,
897 targets: Vec<Self::AccountId>,
898 voters: Vec<(
899 Self::AccountId,
900 VoteWeight,
901 impl Clone + IntoIterator<Item = Self::AccountId>,
902 )>,
903 ) -> Result<ElectionResult<Self::AccountId, Self::Accuracy>, Self::Error> {
904 sp_npos_elections::phragmms(winners, targets, voters, Balancing::get())
905 }
906
907 fn weight<T: WeightInfo>(voters: u32, targets: u32, vote_degree: u32) -> Weight {
908 T::phragmms(voters, targets, vote_degree)
909 }
910}
911
912pub type Voter<AccountId, Bound> = (AccountId, VoteWeight, BoundedVec<AccountId, Bound>);
914
915pub type VoterOf<D> =
917 Voter<<D as ElectionDataProvider>::AccountId, <D as ElectionDataProvider>::MaxVotesPerVoter>;
918
919#[derive(
921 Default, Debug, Encode, Decode, DecodeWithMemTracking, scale_info::TypeInfo, MaxEncodedLen,
922)]
923#[codec(mel_bound(AccountId: MaxEncodedLen, Bound: Get<u32>))]
924#[scale_info(skip_type_params(Bound))]
925pub struct BoundedSupport<AccountId, Bound: Get<u32>> {
926 pub total: ExtendedBalance,
928 pub voters: BoundedVec<(AccountId, ExtendedBalance), Bound>,
930}
931
932impl<AccountId, Bound: Get<u32>> sp_npos_elections::Backings for &BoundedSupport<AccountId, Bound> {
933 fn total(&self) -> ExtendedBalance {
934 self.total
935 }
936}
937
938impl<AccountId: PartialEq, Bound: Get<u32>> PartialEq for BoundedSupport<AccountId, Bound> {
939 fn eq(&self, other: &Self) -> bool {
940 self.total == other.total && self.voters == other.voters
941 }
942}
943
944impl<AccountId, Bound: Get<u32>> From<BoundedSupport<AccountId, Bound>> for Support<AccountId> {
945 fn from(b: BoundedSupport<AccountId, Bound>) -> Self {
946 Support { total: b.total, voters: b.voters.into_inner() }
947 }
948}
949
950impl<AccountId: Clone, Bound: Get<u32>> Clone for BoundedSupport<AccountId, Bound> {
951 fn clone(&self) -> Self {
952 Self { voters: self.voters.clone(), total: self.total }
953 }
954}
955
956impl<AccountId, Bound: Get<u32>> TryFrom<sp_npos_elections::Support<AccountId>>
957 for BoundedSupport<AccountId, Bound>
958{
959 type Error = &'static str;
960 fn try_from(s: sp_npos_elections::Support<AccountId>) -> Result<Self, Self::Error> {
961 let voters = s.voters.try_into().map_err(|_| "voters bound not respected")?;
962 Ok(Self { voters, total: s.total })
963 }
964}
965
966impl<AccountId: Clone, Bound: Get<u32>> BoundedSupport<AccountId, Bound> {
967 pub fn sorted_truncate_from(mut support: sp_npos_elections::Support<AccountId>) -> (Self, u32) {
972 if let Ok(bounded) = support.clone().try_into() {
974 return (bounded, 0)
975 }
976
977 let pre_len = support.voters.len();
978 support.voters.sort_by(|a, b| a.1.cmp(&b.1));
982 let mut bounded = Self { voters: Default::default(), total: 0 };
984 while let Some((voter, weight)) = support.voters.pop() {
985 if let Err(_) = bounded.voters.try_push((voter, weight)) {
986 break
987 }
988 bounded.total += weight;
989 }
990 let post_len = bounded.voters.len();
991 (bounded, (pre_len - post_len) as u32)
992 }
993}
994
995#[derive(Encode, Decode, DecodeWithMemTracking, TypeInfo, DefaultNoBound, MaxEncodedLen)]
1003#[codec(mel_bound(AccountId: MaxEncodedLen, BOuter: Get<u32>, BInner: Get<u32>))]
1004#[scale_info(skip_type_params(BOuter, BInner))]
1005pub struct BoundedSupports<AccountId, BOuter: Get<u32>, BInner: Get<u32>>(
1006 pub BoundedVec<(AccountId, BoundedSupport<AccountId, BInner>), BOuter>,
1007);
1008
1009pub trait TryFromOtherBounds<AccountId, BOtherOuter: Get<u32>, BOtherInner: Get<u32>> {
1011 fn try_from_other_bounds(
1012 other: BoundedSupports<AccountId, BOtherOuter, BOtherInner>,
1013 ) -> Result<Self, crate::Error>
1014 where
1015 Self: Sized;
1016}
1017
1018impl<
1019 AccountId,
1020 BOuter: Get<u32>,
1021 BInner: Get<u32>,
1022 BOtherOuter: Get<u32>,
1023 BOuterInner: Get<u32>,
1024 > TryFromOtherBounds<AccountId, BOtherOuter, BOuterInner>
1025 for BoundedSupports<AccountId, BOuter, BInner>
1026{
1027 fn try_from_other_bounds(
1028 other: BoundedSupports<AccountId, BOtherOuter, BOuterInner>,
1029 ) -> Result<Self, crate::Error> {
1030 if BOtherOuter::get() <= BOuter::get() && BOuterInner::get() <= BInner::get() {
1032 let supports = other
1034 .into_iter()
1035 .map(|(acc, b_support)| {
1036 b_support
1037 .try_into()
1038 .defensive_map_err(|_| Error::BoundsExceeded)
1039 .map(|b_support| (acc, b_support))
1040 })
1041 .collect::<Result<Vec<_>, _>>()
1042 .defensive()?;
1043 supports.try_into()
1044 } else {
1045 Err(crate::Error::BoundsExceeded)
1046 }
1047 }
1048}
1049
1050impl<AccountId: Clone, BOuter: Get<u32>, BInner: Get<u32>>
1051 BoundedSupports<AccountId, BOuter, BInner>
1052{
1053 pub fn sorted_truncate_from(supports: Supports<AccountId>) -> (Self, u32, u32) {
1058 if let Ok(bounded) = supports.clone().try_into() {
1060 return (bounded, 0, 0)
1061 }
1062
1063 let pre_winners = supports.len();
1064 let mut backers_removed = 0;
1065 let mut inner_supports = supports
1067 .into_iter()
1068 .map(|(account, support)| {
1069 let (bounded, removed) =
1070 BoundedSupport::<AccountId, BInner>::sorted_truncate_from(support);
1071 backers_removed += removed;
1072 (account, bounded)
1073 })
1074 .collect::<Vec<_>>();
1075
1076 inner_supports.sort_by(|a, b| b.1.total.cmp(&a.1.total));
1078
1079 let bounded = BoundedSupports(BoundedVec::<
1081 (AccountId, BoundedSupport<AccountId, BInner>),
1082 BOuter,
1083 >::truncate_from(inner_supports));
1084 let post_winners = bounded.len();
1085 (bounded, (pre_winners - post_winners) as u32, backers_removed)
1086 }
1087}
1088
1089pub trait TryFromUnboundedPagedSupports<AccountId, BOuter: Get<u32>, BInner: Get<u32>> {
1091 fn try_from_unbounded_paged(
1092 self,
1093 ) -> Result<Vec<BoundedSupports<AccountId, BOuter, BInner>>, crate::Error>
1094 where
1095 Self: Sized;
1096}
1097
1098impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>>
1099 TryFromUnboundedPagedSupports<AccountId, BOuter, BInner> for Vec<Supports<AccountId>>
1100{
1101 fn try_from_unbounded_paged(
1102 self,
1103 ) -> Result<Vec<BoundedSupports<AccountId, BOuter, BInner>>, crate::Error> {
1104 self.into_iter()
1105 .map(|s| s.try_into().map_err(|_| crate::Error::BoundsExceeded))
1106 .collect::<Result<Vec<_>, _>>()
1107 }
1108}
1109
1110impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> sp_npos_elections::EvaluateSupport
1111 for BoundedSupports<AccountId, BOuter, BInner>
1112{
1113 fn evaluate(&self) -> sp_npos_elections::ElectionScore {
1114 sp_npos_elections::evaluate_support(self.iter().map(|(_, s)| s))
1115 }
1116}
1117
1118impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> sp_std::ops::DerefMut
1119 for BoundedSupports<AccountId, BOuter, BInner>
1120{
1121 fn deref_mut(&mut self) -> &mut Self::Target {
1122 &mut self.0
1123 }
1124}
1125
1126impl<AccountId: Debug, BOuter: Get<u32>, BInner: Get<u32>> Debug
1127 for BoundedSupports<AccountId, BOuter, BInner>
1128{
1129 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1130 for s in self.0.iter() {
1131 write!(f, "({:?}, {:?}, {:?}) ", s.0, s.1.total, s.1.voters)?;
1132 }
1133 Ok(())
1134 }
1135}
1136
1137impl<AccountId: PartialEq, BOuter: Get<u32>, BInner: Get<u32>> PartialEq
1138 for BoundedSupports<AccountId, BOuter, BInner>
1139{
1140 fn eq(&self, other: &Self) -> bool {
1141 self.0 == other.0
1142 }
1143}
1144
1145impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> Into<Supports<AccountId>>
1146 for BoundedSupports<AccountId, BOuter, BInner>
1147{
1148 fn into(self) -> Supports<AccountId> {
1149 self.0.into_iter().map(|(acc, b_support)| (acc, b_support.into())).collect()
1151 }
1152}
1153
1154impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>>
1155 From<BoundedVec<(AccountId, BoundedSupport<AccountId, BInner>), BOuter>>
1156 for BoundedSupports<AccountId, BOuter, BInner>
1157{
1158 fn from(t: BoundedVec<(AccountId, BoundedSupport<AccountId, BInner>), BOuter>) -> Self {
1159 Self(t)
1160 }
1161}
1162
1163impl<AccountId: Clone, BOuter: Get<u32>, BInner: Get<u32>> Clone
1164 for BoundedSupports<AccountId, BOuter, BInner>
1165{
1166 fn clone(&self) -> Self {
1167 Self(self.0.clone())
1168 }
1169}
1170
1171impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> sp_std::ops::Deref
1172 for BoundedSupports<AccountId, BOuter, BInner>
1173{
1174 type Target = BoundedVec<(AccountId, BoundedSupport<AccountId, BInner>), BOuter>;
1175
1176 fn deref(&self) -> &Self::Target {
1177 &self.0
1178 }
1179}
1180
1181impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> IntoIterator
1182 for BoundedSupports<AccountId, BOuter, BInner>
1183{
1184 type Item = (AccountId, BoundedSupport<AccountId, BInner>);
1185 type IntoIter = sp_std::vec::IntoIter<Self::Item>;
1186
1187 fn into_iter(self) -> Self::IntoIter {
1188 self.0.into_iter()
1189 }
1190}
1191
1192impl<AccountId, BOuter: Get<u32>, BInner: Get<u32>> TryFrom<Supports<AccountId>>
1193 for BoundedSupports<AccountId, BOuter, BInner>
1194{
1195 type Error = crate::Error;
1196
1197 fn try_from(supports: Supports<AccountId>) -> Result<Self, Self::Error> {
1198 let mut outer_bounded_supports = BoundedVec::<
1200 (AccountId, BoundedSupport<AccountId, BInner>),
1201 BOuter,
1202 >::with_bounded_capacity(
1203 supports.len().min(BOuter::get() as usize)
1204 );
1205
1206 supports
1208 .into_iter()
1209 .map(|(account, support)| (account, support.try_into().map_err(|_| ())))
1210 .try_for_each(|(account, maybe_bounded_supports)| {
1211 outer_bounded_supports
1212 .try_push((account, maybe_bounded_supports?))
1213 .map_err(|_| ())
1214 })
1215 .map_err(|_| crate::Error::BoundsExceeded)?;
1216
1217 Ok(outer_bounded_supports.into())
1218 }
1219}
1220
1221pub type BoundedSupportsOf<E> = BoundedSupports<
1223 <E as ElectionProvider>::AccountId,
1224 <E as ElectionProvider>::MaxWinnersPerPage,
1225 <E as ElectionProvider>::MaxBackersPerWinner,
1226>;
1227
1228sp_core::generate_feature_enabled_macro!(
1229 runtime_benchmarks_enabled,
1230 feature = "runtime-benchmarks",
1231 $
1232);
1233
1234sp_core::generate_feature_enabled_macro!(
1235 runtime_benchmarks_or_std_enabled,
1236 any(feature = "runtime-benchmarks", feature = "std"),
1237 $
1238);