Enforce MaxEncodedLen impl for NposSolution (#11103)

* Fail if `MaxVoters` too small

* Fixing benchmarking test, better naming of error

* reverting accidental change

* use fully qualified syntax
no need to interate to calculate len

* Fail directly if too many voters
This commit is contained in:
Georges
2022-03-31 13:54:44 +01:00
committed by GitHub
parent 7bf19fa9c9
commit 0e0d0a677a
6 changed files with 40 additions and 4 deletions
@@ -124,6 +124,11 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
for<'r> FV: Fn(&'r A) -> Option<Self::VoterIndex>,
for<'r> FT: Fn(&'r A) -> Option<Self::TargetIndex>,
{
// Make sure that the voter bound is binding.
// `assignments.len()` actually represents the number of voters
if assignments.len() as u32 > <#max_voters as _feps::Get<u32>>::get() {
return Err(_feps::Error::TooManyVoters);
}
let mut #struct_name: #ident = Default::default();
for _feps::Assignment { who, distribution } in assignments {
match distribution.len() {
@@ -134,6 +139,7 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result<TokenStream2> {
}
}
};
Ok(#struct_name)
}
@@ -170,12 +170,13 @@ pub mod onchain;
pub mod traits;
#[cfg(feature = "std")]
use codec::{Decode, Encode};
use frame_support::{traits::Get, BoundedVec, RuntimeDebug};
use frame_support::{BoundedVec, RuntimeDebug};
use sp_runtime::traits::Bounded;
use sp_std::{fmt::Debug, prelude::*};
/// Re-export the solution generation macro.
pub use frame_election_provider_solution_type::generate_solution_type;
pub use frame_support::traits::Get;
/// Re-export some type as they are used in the interface.
pub use sp_arithmetic::PerThing;
pub use sp_npos_elections::{
@@ -47,7 +47,7 @@ crate::generate_solution_type! {
VoterIndex = u32,
TargetIndex = u16,
Accuracy = TestAccuracy,
MaxVoters = frame_support::traits::ConstU32::<20>,
MaxVoters = frame_support::traits::ConstU32::<2_500>,
>(16)
}
@@ -91,6 +91,33 @@ mod solution_type {
assert!(with_compact < without_compact);
}
#[test]
fn from_assignment_fail_too_many_voters() {
let rng = rand::rngs::SmallRng::seed_from_u64(0);
// This will produce 24 voters..
let (voters, assignments, candidates) = generate_random_votes(10, 25, rng);
let voter_index = make_voter_fn(&voters);
let target_index = make_target_fn(&candidates);
// Limit the voters to 20..
generate_solution_type!(
pub struct InnerTestSolution::<
VoterIndex = u32,
TargetIndex = u16,
Accuracy = TestAccuracy,
MaxVoters = frame_support::traits::ConstU32::<20>,
>(16)
);
// 24 > 20, so this should fail.
assert_eq!(
InnerTestSolution::from_assignment(&assignments, &voter_index, &target_index)
.unwrap_err(),
NposError::TooManyVoters,
);
}
#[test]
fn max_encoded_len_too_small() {
generate_solution_type!(