Skip to content
Snippets Groups Projects
Commit fc449c8a authored by Kian Paimani's avatar Kian Paimani Committed by GitHub
Browse files

Fix panic in election-provider offchain worker. (#8732)

parent 6e8957b0
Branches
No related merge requests found
...@@ -437,6 +437,11 @@ impl<T: Config> Pallet<T> { ...@@ -437,6 +437,11 @@ impl<T: Config> Pallet<T> {
let mut high = assignments.len(); let mut high = assignments.len();
let mut low = 0; let mut low = 0;
// not much we can do if assignments are already empty.
if high == low {
return Ok(());
}
while high - low > 1 { while high - low > 1 {
let test = (high + low) / 2; let test = (high + low) / 2;
if encoded_size_of(&assignments[..test])? <= max_allowed_length { if encoded_size_of(&assignments[..test])? <= max_allowed_length {
...@@ -446,13 +451,13 @@ impl<T: Config> Pallet<T> { ...@@ -446,13 +451,13 @@ impl<T: Config> Pallet<T> {
} }
} }
let maximum_allowed_voters = let maximum_allowed_voters =
if encoded_size_of(&assignments[..low + 1])? <= max_allowed_length { if low < assignments.len() && encoded_size_of(&assignments[..low + 1])? <= max_allowed_length {
low + 1 low + 1
} else { } else {
low low
}; };
// ensure our postconditions are correct // ensure our post-conditions are correct
debug_assert!( debug_assert!(
encoded_size_of(&assignments[..maximum_allowed_voters]).unwrap() <= max_allowed_length encoded_size_of(&assignments[..maximum_allowed_voters]).unwrap() <= max_allowed_length
); );
...@@ -1256,8 +1261,7 @@ mod tests { ...@@ -1256,8 +1261,7 @@ mod tests {
#[test] #[test]
fn trim_assignments_length_does_not_modify_when_short_enough() { fn trim_assignments_length_does_not_modify_when_short_enough() {
let mut ext = ExtBuilder::default().build(); ExtBuilder::default().build_and_execute(|| {
ext.execute_with(|| {
roll_to(25); roll_to(25);
// given // given
...@@ -1281,8 +1285,7 @@ mod tests { ...@@ -1281,8 +1285,7 @@ mod tests {
#[test] #[test]
fn trim_assignments_length_modifies_when_too_long() { fn trim_assignments_length_modifies_when_too_long() {
let mut ext = ExtBuilder::default().build(); ExtBuilder::default().build().execute_with(|| {
ext.execute_with(|| {
roll_to(25); roll_to(25);
// given // given
...@@ -1307,8 +1310,7 @@ mod tests { ...@@ -1307,8 +1310,7 @@ mod tests {
#[test] #[test]
fn trim_assignments_length_trims_lowest_stake() { fn trim_assignments_length_trims_lowest_stake() {
let mut ext = ExtBuilder::default().build(); ExtBuilder::default().build().execute_with(|| {
ext.execute_with(|| {
roll_to(25); roll_to(25);
// given // given
...@@ -1340,13 +1342,59 @@ mod tests { ...@@ -1340,13 +1342,59 @@ mod tests {
}); });
} }
#[test]
fn trim_assignments_length_wont_panic() {
// we shan't panic if assignments are initially empty.
ExtBuilder::default().build_and_execute(|| {
let encoded_size_of = Box::new(|assignments: &[IndexAssignmentOf<Runtime>]| {
CompactOf::<Runtime>::try_from(assignments).map(|compact| compact.encoded_size())
});
let mut assignments = vec![];
// since we have 16 fields, we need to store the length fields of 16 vecs, thus 16 bytes
// minimum.
let min_compact_size = encoded_size_of(&assignments).unwrap();
assert_eq!(min_compact_size, CompactOf::<Runtime>::LIMIT);
// all of this should not panic.
MultiPhase::trim_assignments_length(0, &mut assignments, encoded_size_of.clone())
.unwrap();
MultiPhase::trim_assignments_length(1, &mut assignments, encoded_size_of.clone())
.unwrap();
MultiPhase::trim_assignments_length(
min_compact_size as u32,
&mut assignments,
encoded_size_of,
)
.unwrap();
});
// or when we trim it to zero.
ExtBuilder::default().build_and_execute(|| {
// we need snapshot for `trim_helpers` to work.
roll_to(25);
let TrimHelpers { mut assignments, encoded_size_of, .. } = trim_helpers();
assert!(assignments.len() > 0);
// trim to min compact size.
let min_compact_size = CompactOf::<Runtime>::LIMIT as u32;
MultiPhase::trim_assignments_length(
min_compact_size,
&mut assignments,
encoded_size_of,
)
.unwrap();
assert_eq!(assignments.len(), 0);
});
}
// all the other solution-generation functions end up delegating to `mine_solution`, so if we // all the other solution-generation functions end up delegating to `mine_solution`, so if we
// demonstrate that `mine_solution` solutions are all trimmed to an acceptable length, then // demonstrate that `mine_solution` solutions are all trimmed to an acceptable length, then
// we know that higher-level functions will all also have short-enough solutions. // we know that higher-level functions will all also have short-enough solutions.
#[test] #[test]
fn mine_solution_solutions_always_within_acceptable_length() { fn mine_solution_solutions_always_within_acceptable_length() {
let mut ext = ExtBuilder::default().build(); ExtBuilder::default().build_and_execute(|| {
ext.execute_with(|| {
roll_to(25); roll_to(25);
// how long would the default solution be? // how long would the default solution be?
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment