pallet_election_provider_multi_block/
types.rs1use crate::{unsigned::miner::MinerConfig, verifier};
39use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
40use frame_election_provider_support::ElectionProvider;
41pub use frame_election_provider_support::{NposSolution, PageIndex};
42use frame_support::{
43 traits::DefensiveSaturating, BoundedVec, CloneNoBound, DebugNoBound, DefaultNoBound, EqNoBound,
44 PartialEqNoBound,
45};
46use frame_system::pallet_prelude::BlockNumberFor;
47use scale_info::TypeInfo;
48use sp_core::Get;
49pub use sp_npos_elections::{ElectionResult, ElectionScore};
50use sp_runtime::{
51 traits::{CheckedSub, One, Zero},
52 SaturatedConversion, Saturating,
53};
54use sp_std::{collections::btree_set::BTreeSet, fmt::Debug, prelude::*};
55
56pub type SolutionOf<T> = <T as MinerConfig>::Solution;
58pub type SolutionVoterIndexOf<T> = <SolutionOf<T> as NposSolution>::VoterIndex;
60pub type SolutionTargetIndexOf<T> = <SolutionOf<T> as NposSolution>::TargetIndex;
62pub type SolutionAccuracyOf<T> = <SolutionOf<T> as NposSolution>::Accuracy;
64pub type FallbackErrorOf<T> = <<T as crate::Config>::Fallback as ElectionProvider>::Error;
66
67pub type AssignmentOf<T> =
69 sp_npos_elections::Assignment<<T as MinerConfig>::AccountId, SolutionAccuracyOf<T>>;
70
71#[derive(
77 TypeInfo,
78 Encode,
79 Decode,
80 DecodeWithMemTracking,
81 DebugNoBound,
82 CloneNoBound,
83 EqNoBound,
84 PartialEqNoBound,
85 DefaultNoBound,
86)]
87#[codec(mel_bound(T: crate::Config))]
88#[scale_info(skip_type_params(T))]
89pub struct PagedRawSolution<T: MinerConfig> {
90 pub solution_pages: Vec<SolutionOf<T>>,
92 pub score: ElectionScore,
94 pub round: u32,
96}
97
98impl<T: MinerConfig> PagedRawSolution<T> {
99 pub fn voter_count(&self) -> usize {
101 self.solution_pages
102 .iter()
103 .map(|page| page.voter_count())
104 .fold(0usize, |acc, x| acc.saturating_add(x))
105 }
106
107 pub fn winner_count_single_page_target_snapshot(&self) -> usize {
109 self.solution_pages
110 .iter()
111 .map(|page| page.unique_targets())
112 .into_iter()
113 .flatten()
114 .collect::<BTreeSet<_>>()
115 .len()
116 }
117
118 pub fn edge_count(&self) -> usize {
120 self.solution_pages
121 .iter()
122 .map(|page| page.edge_count())
123 .fold(0usize, |acc, x| acc.saturating_add(x))
124 }
125}
126
127pub trait Pagify<T> {
137 fn pagify(&self, bound: PageIndex) -> Box<dyn Iterator<Item = (PageIndex, &T)> + '_>;
139}
140
141impl<T> Pagify<T> for Vec<T> {
142 fn pagify(&self, desired_pages: PageIndex) -> Box<dyn Iterator<Item = (PageIndex, &T)> + '_> {
143 Box::new(
144 self.into_iter()
145 .enumerate()
146 .map(|(p, s)| (p.saturated_into::<PageIndex>(), s))
147 .map(move |(p, s)| {
148 let desired_pages_usize = desired_pages as usize;
149 debug_assert!(self.len() <= desired_pages_usize);
151 let padding = desired_pages_usize.saturating_sub(self.len());
152 let new_page = p.saturating_add(padding.saturated_into::<PageIndex>());
153 (new_page, s)
154 }),
155 )
156 }
157}
158
159pub trait PadSolutionPages: Sized {
163 fn pad_solution_pages(self, desired_pages: PageIndex) -> Self;
165}
166
167impl<T: Default + Clone + Debug> PadSolutionPages for Vec<T> {
168 fn pad_solution_pages(self, desired_pages: PageIndex) -> Self {
169 let desired_pages_usize = desired_pages as usize;
170 debug_assert!(self.len() <= desired_pages_usize);
171 if self.len() == desired_pages_usize {
172 return self
173 }
174
175 let empty_slots = desired_pages_usize.saturating_sub(self.len());
177 sp_std::iter::repeat(Default::default())
178 .take(empty_slots)
179 .chain(self.into_iter())
180 .collect::<Vec<_>>()
181 }
182}
183
184impl<T: Default + Clone + Debug, Bound: frame_support::traits::Get<u32>> PadSolutionPages
185 for BoundedVec<T, Bound>
186{
187 fn pad_solution_pages(self, desired_pages: PageIndex) -> Self {
188 let desired_pages_usize = (desired_pages).min(Bound::get()) as usize;
189 debug_assert!(self.len() <= desired_pages_usize);
190 if self.len() == desired_pages_usize {
191 return self
192 }
193
194 let empty_slots = desired_pages_usize.saturating_sub(self.len());
196 let self_as_vec = sp_std::iter::repeat(Default::default())
197 .take(empty_slots)
198 .chain(self.into_iter())
199 .collect::<Vec<_>>();
200 self_as_vec.try_into().expect("sum of both iterators has at most `desired_pages_usize` items; `desired_pages_usize` is `min`-ed by `Bound`; conversion cannot fail; qed")
201 }
202}
203
204pub type VoterOf<T> = frame_election_provider_support::Voter<
206 <T as MinerConfig>::AccountId,
207 <T as MinerConfig>::MaxVotesPerVoter,
208>;
209
210pub type VoterPageOf<T> = BoundedVec<VoterOf<T>, <T as MinerConfig>::VoterSnapshotPerBlock>;
212
213pub type AllVoterPagesOf<T> = BoundedVec<VoterPageOf<T>, <T as MinerConfig>::Pages>;
215
216pub struct MaxFlattenedVoters<T: MinerConfig>(sp_std::marker::PhantomData<T>);
218impl<T: MinerConfig> Get<u32> for MaxFlattenedVoters<T> {
219 fn get() -> u32 {
220 T::VoterSnapshotPerBlock::get().saturating_mul(T::Pages::get())
221 }
222}
223
224pub type AllVoterPagesFlattenedOf<T> = BoundedVec<VoterOf<T>, MaxFlattenedVoters<T>>;
229
230#[derive(
232 PartialEqNoBound,
233 EqNoBound,
234 CloneNoBound,
235 Encode,
236 Decode,
237 DecodeWithMemTracking,
238 MaxEncodedLen,
239 DebugNoBound,
240 TypeInfo,
241)]
242#[codec(mel_bound(T: crate::Config))]
243#[scale_info(skip_type_params(T))]
244pub enum Phase<T: crate::Config> {
245 Off,
247 Signed(BlockNumberFor<T>),
251 SignedValidation(BlockNumberFor<T>),
258 Unsigned(BlockNumberFor<T>),
270 Snapshot(PageIndex),
277 Done,
279 Export(PageIndex),
283 Emergency,
286}
287
288impl<T: crate::Config> Copy for Phase<T> {}
289
290impl<T: crate::Config> Default for Phase<T> {
291 fn default() -> Self {
292 Phase::Off
293 }
294}
295
296impl<T: crate::Config> Phase<T> {
297 pub(crate) fn start_phase() -> Self {
299 Self::Snapshot(T::Pages::get())
302 }
303
304 fn are_we_done() -> Self {
305 let query = T::AreWeDone::get();
306 query
307 }
308
309 fn verifier_done() -> bool {
312 matches!(
313 <T::Verifier as verifier::AsynchronousVerifier>::status(),
314 verifier::Status::Nothing
315 )
316 }
317
318 pub fn next(self) -> Self {
320 match self {
321 Self::Off => Self::Off,
323 Self::Emergency => Self::Emergency,
324
325 Self::Snapshot(0) =>
327 if let Some(signed_duration) = T::SignedPhase::get().checked_sub(&One::one()) {
328 Self::Signed(signed_duration)
329 } else if let Some(unsigned_duration) =
330 T::UnsignedPhase::get().checked_sub(&One::one())
331 {
332 Self::Unsigned(unsigned_duration)
333 } else {
334 Self::are_we_done()
335 },
336 Self::Snapshot(non_zero_remaining) =>
337 Self::Snapshot(non_zero_remaining.defensive_saturating_sub(One::one())),
338
339 Self::Signed(zero) if zero == BlockNumberFor::<T>::zero() =>
341 Self::SignedValidation(T::SignedValidationPhase::get()),
342 Self::Signed(non_zero_left) =>
343 Self::Signed(non_zero_left.defensive_saturating_sub(One::one())),
344
345 Self::SignedValidation(zero)
347 if zero == BlockNumberFor::<T>::zero() && Self::verifier_done() =>
348 if let Some(unsigned_duration) = T::UnsignedPhase::get().checked_sub(&One::one()) {
349 Self::Unsigned(unsigned_duration)
350 } else {
351 Self::are_we_done()
352 },
353 Self::SignedValidation(non_zero_left) =>
354 Self::SignedValidation(non_zero_left.saturating_sub(One::one())),
355
356 Self::Unsigned(zero) if zero == BlockNumberFor::<T>::zero() => Self::are_we_done(),
358 Self::Unsigned(non_zero_left) =>
359 Self::Unsigned(non_zero_left.defensive_saturating_sub(One::one())),
360
361 Self::Done => Self::Done,
363
364 Self::Export(x) => Self::Export(x),
367 }
368 }
369
370 pub fn is_emergency(&self) -> bool {
372 matches!(self, Phase::Emergency)
373 }
374
375 pub fn is_signed(&self) -> bool {
377 matches!(self, Phase::Signed(_))
378 }
379
380 pub fn is_unsigned(&self) -> bool {
382 matches!(self, Phase::Unsigned(_))
383 }
384
385 pub fn is_off(&self) -> bool {
387 matches!(self, Phase::Off)
388 }
389
390 pub fn is_snapshot(&self) -> bool {
392 matches!(self, Phase::Snapshot(_))
393 }
394
395 pub fn is_done(&self) -> bool {
397 matches!(self, Phase::Done)
398 }
399
400 pub fn is_export(&self) -> bool {
402 matches!(self, Phase::Export(_))
403 }
404
405 pub fn is_signed_validation(&self) -> bool {
407 matches!(self, Phase::SignedValidation(_))
408 }
409
410 pub fn is_signed_validation_opened_now(&self) -> bool {
412 self == &Phase::SignedValidation(T::SignedValidationPhase::get().saturating_sub(One::one()))
413 }
414
415 pub fn is_unsigned_opened_now(&self) -> bool {
417 self == &Phase::Unsigned(T::UnsignedPhase::get().saturating_sub(One::one()))
418 }
419}
420
421pub trait SignedInterface {
426 fn has_leader(round: u32) -> bool;
428}
429
430#[cfg(test)]
431mod pagify {
432 use super::{PadSolutionPages, Pagify};
433
434 #[test]
435 fn pagify_works() {
436 assert_eq!(
438 vec![10, 11, 12].pagify(3).collect::<Vec<_>>(),
439 vec![(0, &10), (1, &11), (2, &12)]
440 );
441
442 assert_eq!(vec![10, 11].pagify(3).collect::<Vec<_>>(), vec![(1, &10), (2, &11)]);
444 assert_eq!(vec![10].pagify(3).collect::<Vec<_>>(), vec![(2, &10)]);
445 }
446
447 #[test]
448 fn pad_solution_pages_works() {
449 let solution = vec![1u32, 2, 3];
451 assert_eq!(solution.pad_solution_pages(3), vec![1, 2, 3]);
452
453 let solution = vec![2, 3];
455 assert_eq!(solution.pad_solution_pages(3), vec![0, 2, 3]);
456 }
457}